LINUX.ORG.RU

Как организовать автовыгрузку из свопа?

 


1

1

Ситуация следующая. Запускается программа А, которая занимает какую-то часть памяти. Запускается программа Б, которой не хватает оставшейся свободной памяти, поэтому программа А отправляется в своп. После закрытия программы Б, программа А остаётся в свопе и из-за этого люто тормозит. Приходится делать swapoff -a и swapon -a чтоб вернуть прежнюю отзывчивость.

Вопрос: есть ли способы настроить поведение таким образом, чтоб при освобождении памяти система автоматически доставала данные из свопа не дожидаясь момента, когда они понадобятся?

★★

Так тогда будет же тормозить при освобождении памяти.

Может, лучше zram настроить, сделать на нем swap-раздел и поставить его самым приоритетным?

squareroot ★★★★
()
Ответ на: комментарий от anonymous

Чтобы не ждать, можно для программы Б враппер написать на пару строк:

#!/bin/sh
programma_Be "$@"

# на всякий случай убеждаемся, что программ Б точно завершилась
# если она «нормальная», то можно и без этого цикла, но мало ли
while : do
    ps x | grep '[p]rogramma_Be' > /dev/null || break
    sleep 1
    # а можно и проверку на наличие достаточного количества свободной памяти добавить, если уж по уму
done

swapoff -a
swapon -a

Положить его в /usr/local/bin с именем программы Б, и запускать так, соответственно.

CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 2)
Ответ на: комментарий от anonymous

@CrX

Это запасной вариант - повесть на одну из системных кнопок, которую обрабатывает acpid, скрипт swapoff -a && swapon -a, но пока подожду, может кто знает решение с автоматической обработкой. Я в сети найти не смог.

u5er ★★
() автор топика
Последнее исправление: u5er (всего исправлений: 1)

Ты познал прелести свопа на диске, я которых я уже писал. А что ты запускаешь, жрущее своп? Единственный вариант - переписать прогу, отрубив своп, будешь ее переписывать, пока она падать прекратит. Только так можно научиться работать с памятью.

rtxtxtrx ★★
()
Ответ на: комментарий от rtxtxtrx

Ты познал прелести свопа на диске, я которых я уже писал

Я их познал ещё в те годы, когда только начал пользоваться линуксом :)

А что ты запускаешь, жрущее своп?

Кикад при добавлении элементов грузит всю свою базу и это отъедает порядка 3.5 гигов из 4 установленных. Если перед кикадом запустить ещё софта, то начинается вот это вот всё.

u5er ★★
() автор топика

После закрытия программы Б, программа А остаётся в свопе и из-за этого люто тормозит.

Видится мне, что озвученное в первом комменте темы (zswap/zram) ближе к решению, ибо делает своп более производительным.
Плюс, ядро 6.13, со всеми последними патчами MGLRU, добавит отзывчивости системе при интенсивном обмене данными свопа с ram.

А вот очистка свопа, это уже «Проблема XY», имхо.

krasnh ★★★★
()

Не совсем понятно, по какому принципу такая выгрузка должна происходить. Ты хочешь постоянной 100%-ой загрузки памяти и тормошение свопа туда-сюда? Когда освободилось немного рамы, сразу лезем в своп и выгружаем что нашли? А как надо снова памяти, выгружаем что-то в свап опять?

Gary ★★★★★
()
Ответ на: комментарий от Gary

Когда освободилось немного рамы, сразу лезем в своп и выгружаем что нашли? А как надо снова памяти, выгружаем что-то в свап опять?

Да. Разумеется, что должен быть некий «гистерезис», но всё же когда есть достаточное количество свободной рамы, то хотелось бы, чтоб данные доставались из свопа автоматически.

u5er ★★
() автор топика
Последнее исправление: u5er (всего исправлений: 1)

Вопрос: есть ли способы настроить поведение таким образом, чтоб при освобождении памяти система автоматически доставала данные из свопа не дожидаясь момента, когда они понадобятся?

Вроде бы нет, но можно запускать программы в отдельных cgroups каждая, а внутри него уже регулировать количество памяти и свопа. Можно также указать минимальное количество используемой памяти, чтобы одна из программ (которая должна оставаться отзывчивой) никогда/почти никогда не выгружалась.

Альтернативный вариант — mlockall.

ValdikSS ★★★★★
()
Ответ на: комментарий от u5er

Оффтоп — XY problem во всей своей красе.

Кикад при добавлении элементов грузит всю свою базу

Можно просто задать в настройках ограниченный список библиотек и не грузить всё подряд. Сомневаюсь, что у вас проект, использующий каждую детальку из доступных.

anonymous
()

Ради эксперимента, написал утилиту для принудительной выгрузки/загрузки из свопа конкретного процесса (все анонимные страницы)

Нужен root. С++.

$ ./pswap
ERROR: Usage: [sudo] ./pswap PID [swapin | swapout | in | out]

Примеры:

По умолчанию, если не указан второй аргумент, выгружает в своп, в данном примере firefox.

# pswap $(pgrep firefox)
# pswap $(pgrep firefox) out
# pswap $(pgrep firefox) swapout

Загрузка из свопа

# pswap $(pgrep firefox) in
# pswap $(pgrep firefox) swapin

#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

extern "C" {
#include <sys/mman.h>
#include <sys/pidfd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
}

enum struct SwapAction { SwapOut, SwapIn };

std::vector<iovec> getAnonMaps(pid_t pid) {
  std::vector<iovec> ret;
  std::string mapsPath;
  mapsPath = mapsPath + "/proc/" + std::to_string(pid) + "/maps";
  std::ifstream f(mapsPath);
  std::string line;
  std::cerr << "AnonMaps:" << '\n';
  while (std::getline(f, line)) {
    std::istringstream in(line);
    std::uintptr_t beg, end;
    std::ptrdiff_t off;
    ino_t inode;
    unsigned int major, minor;
    std::string perm, path;
    char c;
    in >> std::hex >> beg >> c >> end;
    in >> perm;
    in >> std::hex >> off;
    in >> std::hex >> major >> c >> minor;
    in >> std::dec >> inode;
    in >> path;
    if (off != 0 || major != 0 || minor != 0 || inode != 0)
      continue;
    if (path != "[heap]" && path != "[stack]" && !path.empty())
      continue;
    std::cerr << std::hex << beg << ' ' << end - beg << ' ' << path << '\n';

    // madvise почему-то не работает с блоками больше 2^31
    // (воспринимает длину как знаковый int32_t ?!)
    // делим по 2^30 (c запасом)
    static constexpr size_t BlockMax = (1ul << 30);
    for (std::uintptr_t b = beg; b < end; b += BlockMax) {
      iovec v;
      v.iov_base = reinterpret_cast<void*>(b);
      std::size_t l = end - b;
      if (l > BlockMax)
        l = BlockMax;
      v.iov_len = l;
      ret.push_back(v);
    }
  }
  std::cerr << std::endl;
  if (!f.eof())
    throw std::runtime_error("read failed: " + mapsPath);
  return ret;
}

void swapaction(pid_t pid,
                const std::vector<iovec>& maps,
                SwapAction action = SwapAction::SwapOut) {
  int adv = action == SwapAction::SwapOut ? MADV_PAGEOUT : MADV_WILLNEED;
  int pidfd = pidfd_open(pid, 0);
  if (pidfd < 0)
    throw std::runtime_error("cannot access process");
  std::cerr << (action == SwapAction::SwapOut ? "Swap OUT:" : "Swap IN:")
            << '\n';
  for (auto& v : maps) {
    auto r = process_madvise(pidfd, &v, 1, adv, 0);
    if (r < 0)
      throw std::runtime_error(strerror(errno));
    std::cerr << std::hex << v.iov_base << ' ' << v.iov_len << ' ' << r << '\n';
  }
}

void main_exn(int argc, char* argv[]) {
  if (argc < 2 || argc > 3)
    throw std::invalid_argument(
        "Usage: [sudo] ./pswap PID [swapin | swapout | in | out]");
  pid_t pid = std::stoul(argv[1]);
  SwapAction action = SwapAction::SwapOut;
  if (argc == 3) {
    std::string arg2(argv[2]);
    if (arg2 == "in" || arg2 == "swapin")
      action = SwapAction::SwapIn;
    else if (arg2 == "out" || arg2 == "swapout")
      action = SwapAction::SwapOut;
  }
  auto maps = getAnonMaps(pid);
  swapaction(pid, maps, action);
}

int main(int argc, char* argv[]) {
  try {
    main_exn(argc, argv);
    return 0;
  } catch (std::exception& e) {
    std::cerr << "ERROR: " << e.what() << '\n';
    return 1;
  }
}

anonymous
()
Ответ на: комментарий от krasnh

MGLRU добавляет отзывчивости, но ценой меньшего объёма оперативки, доступного для активного софта. Там просто тупо раньше высвобождение и больше резерв «на всякий случай».

Это понятно что тюнингованный своп будет лушче дефолтного, но вот с конкретно поднятием спящей памяти это никак не поможет.

kirill_rrr ★★★★★
()
Ответ на: комментарий от ValdikSS

А вот всё то же самое, но не для групп и программ, а для корневого пирога или сессии юзера? Просто я хз, так настраивается и вообще будет это работать или нет?

kirill_rrr ★★★★★
()
Последнее исправление: kirill_rrr (всего исправлений: 1)
Ответ на: комментарий от Shadow

С этим тоже, тем более что её поведение для конкретной версии ядра малопонятно и будет разным с MGLRU и без него.

Но загуглить и поиграться стоит и со всеми прочими параметрами настройками, хз сколько их всего, я дёргал/дёргаю

echo 0 > /sys/kernel/mm/lru_gen/enabled
echo 64 > /proc/sys/vm/page-cluster
echo 80 > /proc/sys/vm/swappiness
echo 5 > /proc/sys/vm/watermark_scale_factor
#echo 32768 > /proc/sys/vm/min_free_kbytes
и ещё какие то тестировал, но не стал трогать.

kirill_rrr ★★★★★
()

Да, конкретно по автоподнятию ничего не слышал. Костыль с «заскриптовать и повесить на кнопку» тут уже предлагали, потюнинговать работу свопа разумеется полезно, но всё это про процесс выгрузки, а скорость поднятия это исключительно про скорость и отзывчивость диска. Ну и я предполагаю что zram/zswap уже используюется и настроен.

Есть мысль: а что если дёрнуть процесс каким нибудь не знаю, дебаггером/сканером чтобы ядру понадобилось поднять все его страницы?

kirill_rrr ★★★★★
()
Последнее исправление: kirill_rrr (всего исправлений: 1)
Ответ на: комментарий от kirill_rrr

Есть мысль: а что если дёрнуть процесс каким нибудь не знаю, дебаггером/сканером чтобы ядру понадобилось поднять все его страницы?

Это не особо будет отличаться от костыля с заскриптовыванием и повешиванием на кнопку.

u5er ★★
() автор топика
Ответ на: комментарий от u5er

Но идея отключать-подключать своп-раздел это всё таки жесть при которой много чего может пойти не так. А заставить вычитать память процесса/процессов это гарантировано: вычитает, а если сильно надо будет уложит обратно. А так может система лечь если памяти не хватит для отключения свопа.

kirill_rrr ★★★★★
()
Ответ на: комментарий от kirill_rrr

А так может система лечь если памяти не хватит для отключения свопа.

У меня на панели висит показометр занятой памяти и занятого свопа. Если сумма меньше 4х (в моём случае), то можно смело переподключать.

u5er ★★
() автор топика
Ответ на: комментарий от anonymous

zram/zswap будет нагружать проц, во-первых, а данные после упаковки теоретически могут весить даже больше, чем есть свободной оперативки, во-вторых. То есть, при нехватке памяти польза от этого незначительная, а то и отрицательная. Чем больше памяти отдано в zram, чем больше там данных, тем более агрессивное сжатие нужно, но все равно рано или поздно предел будет достигнут и данные будут вытеснены в обычный своп. Наиболее адекватное решение здесь именно добавить оперативки.

yars068 ★★★★
()
Ответ на: комментарий от yars068

Вот не надо. Практика показывает, что очень даже положительная польза, и чем медленней диск и чем меньше пасяти всего - тем больше пользы. И если zram действительно вынужден всё сжимать, то zswap не сжимает несжимаемое. А уж нагрузка от многопоточной работы алгоритмов со скоростью 100-1000 Гб/с/ядро... Это вообще не серьёзно, даже если забыть о том, что приход нехватки памяти сам по себе помножит на ноль загрузку процессора.

kirill_rrr ★★★★★
()
Последнее исправление: kirill_rrr (всего исправлений: 1)
Ответ на: комментарий от kirill_rrr

Неа. Настраивать лень. Позже надо будет zram прикрутить. Вообще, да. Там 1к3 идёт. Если я оставлю 1 гиг в качестве «рабочего» объёма, то в итоге получится 10 гигов «приведёнки».

u5er ★★
() автор топика
Ответ на: комментарий от u5er

Это должно было стать 2-3 пунктом в насройке ОС сразу после подключения физического свопа. Хотя на ssd прирост мало заметен... Ну так i/o сократится.

И лично я предпочитаю zswap а не zram. У них в принципе паритет при правильной настройке, только зачем дополнительная прослойка из виртуального блочного устройства?

kirill_rrr ★★★★★
()
Ответ на: комментарий от kirill_rrr

Это должно было стать 2-3 пунктом в насройке ОС сразу после подключения физического свопа

Я ленивая задница,так что в моём случае это оставляется на «как-нибудь в другой раз».

И лично я предпочитаю zswap а не zram.

А мне больше нравится zram. Я раньше пробовал оба варианта и zswap не оценил. Он сразу пишет на диск, хотя в этом необходимости ещё нет.

u5er ★★
() автор топика
Ответ на: комментарий от u5er

А, да, НЕ НАДО оставлять 1гб в качестве рабочего объёма. меньше 50% жесть может начаться, а например raspberry pi3 с 1гб оперативки много чего в принципе не могла запустить по out of memory когда я оставлял меньше полгига.

kirill_rrr ★★★★★
()
Последнее исправление: kirill_rrr (всего исправлений: 1)
Ответ на: комментарий от ya-betmen

Покрутил. Если поставить 0, то своп не используется вообще и система зависает. Если поставить малое значение, то своп используется, но проблему это не решает - данные всё равно сами не достаются из свопа.

u5er ★★
() автор топика
Ответ на: комментарий от u5er

zswap сразу пишет на диск страницы, которые не удалось сжать. Кстати, с последними патчами и решателем zsmalloc вместо zbud/z3fold проблема может уйти - он будет держать в кеше даже то, что сжалось всего на пару процентов.

kirill_rrr ★★★★★
()
Последнее исправление: kirill_rrr (всего исправлений: 1)
Ответ на: комментарий от kirill_rrr

Зачем он это делает, если место в оперативке ещё есть? Мне больше нравится вариант вариант с zram + swap. zram’у выставляется больший приоритет и вначале используется он. Диск начинает использоваться уже после того, как весь zram заполнится.

u5er ★★
() автор топика
Ответ на: комментарий от kirill_rrr

Это давно было. Я тогда ещё гентушником был. В ходе тестов я выяснил, что zram есть смысл использовать когда на машине более 1 гига рамы. Именно из-за out of memory. В моём случае у меня был ноут с 2 гигами рамы. Я довольно много гонял тестов тогда. В конечном итоге я 1 гиг отдал под zram и он стабильно работал. Получалось в районе 4 гигов «приведёнки».

u5er ★★
() автор топика
Ответ на: комментарий от u5er

Ну, сейчас свопинг начинается заранее или слишком заранее, если ты специально не поджал его к верхнему пределу. Лично я поджал его так, что когда начинается - уже реально пора. Дальше: echo 64 > /proc/sys/vm/page-cluster удлинняем пакет сброса на диск до 64 страницы, т.е. минимум 256Кб и несжимаемое один хрен повисит в буфере прежде чем физически уйти на диск. А ещё я по возможности выделяю для свопинга отдельное устройство и i/o свопинга перестаёт обрушивать производительность системного раздела и хомяка. Так что у меня если сбрасывает значит пусть сбрасывает.

З.Ы. А ещё я тут недавно увидел интерересную штуку в обзорах на ssd: вроде бы сейчас модно проектировать их так, что там нет отдельных чипов slc-кеша, контроллер просто использует «пустые» блоки в slc-режиме вместо tlc. пока диск не заполнится, а потом начнёт переносить и уплотнять информацию. Этим можно воспользоваться просто тупо разметив своп-раздел на 30% дешманского tlc-ssd.

kirill_rrr ★★★★★
()