ЛаТеХ для продвинутых: Как контролировать положение плавающих объектов "floats"?



12 коммент.
О плавающих объектах (например, картинках) в ЛаТеХе написано много книжек, статей, блогов, заметок, и т.д. Тем не менее вопросы вроде: "Почему я поставил там [!h], а ЛаТеХ всё равно засунул картинку на последнюю страницу?", — наверняка войдут в горячую десятку любого ЛаТеХ-форума. Причина этого проста: механизм размещения плавающих объектов (floats) довольно сложен и отнюдь неинтуитивен. Его описания же в основном рассчитаны на докторов физ-мат наук, решивших посвятить остаток своей жизни разборкам с ЛаТеХом. В этом посте я попытаюсь коротко осветить вопрос о том, как можно контролировать расположение плавающих объектов (в качестве примера будут использованны рисунки "figure", но все написанное применимо и к другим floats, например, table). Большая часть поста состоит из рецептов и примеров, исходники которых лежат здесь. Тем не менее, начать придется с небольшого кусочка теории. Итак, ...

Немного теории или "почему ЛаТеХ не делает то, что я хочу?"

Никто не сможет объяснить, как ЛаТеХ помещает флоатс (floats), точнее и лучше, чем сам Франк Миттельбах. Однако поскольку сделал он это на вражеском языке, мы позволим себе здесь повторить коротко его разъяснения.
Когда ЛаТеХ натыкается на плавающий объект в tex-файле, он пытается его немедленно разместить на странице. Страница для ЛаТеХа состоит из двух частей: верхней и нижней. Кроме того, флоат можно поместить "прямо здесь". Да-да, вы уже поняли, что речь пойдёт об этих загадочных буковках "h", "t" и "b" в \begin{figure}[htb]. ЛаТеХ делает следующее:
  1. Если в аргументе в квадратных скобках встречается "h", то ЛаТеХ попытается немедленно поместить плавающий объект.
  2. Если это невозможно, по причинам которые будут объяснены ниже, то ЛаТеХ посмотрит есть ли в аргументе "t". Если да, то он попытается поместить картинку в верхнюю область страницы.
  3. Если уж и тут не вышло, то ЛаТеХ поинтересуется, встречается ли буковка "b". Да? Тогда картинка идет вниз, если это возможно.
  4. В случае, если ничего не получилось, картинка будет помещена в очередь. ЛаТеХ будет пытаться разгрузить эту очередь, как только начнется новая страница. И здесь плевать он хотел на [hbt].
  5. Отдельная песня — это аргумент "p". На него ЛаТеХ обращает внимание только, когда он разгружает очередь после начала новой страницы. Если "есть такая буква в этом слове", то этот плавающий объект может быть размещен на странице без текста с одними только флоатс.
Как вы уже поняли, порядок аргументов ЛаТеХу абсолютно параллелен, то есть [hbt] и [tbh] возымеют абсолютно одинаковый эффект! Если аргументы не указаны, то по умолчанию предполагается [tbp]. Можно или нельзя поместить плавающий объект на текущей странице вверху (или внизу,...) определяется исходя из двух критериев:
  1. максимальное количество флоатс: totalnumber, topnumber, bottomnumber. Параметры эти означают... Ну, вы и сами догадались: максимальное количество флоатс на всей странице, в верхней и в нижней части, по умолчанию, 3, 2 и 1.
  2. размер "верха" и "низа" страницы не должен превышать \topfraction и \bottomfraction доли страницы, соответственно (по-умолчанию, 0.7 и 0.3). Кроме того, доля текста должна быть не менее \textfraction (по-умолчанию, 0.2).
К чему это всё? А к тому, что восклицательный знак ! означает, что эти два правила будут проигнорированны.
Если не предполагается полностью игнорировать все эти правила, то можно изменить значения параметров. Например,
01:  \setcounter{totalnumber}{10}
02:  \setcounter{topnumber}{10}
может пригодиться, если в документе много невысоких картинок. А
01:  \renewcommand{\topfraction}{1}
02:  \renewcommand{\textfraction}{0}
разрешит ЛаТеХу поместить высокую картинку на странице со всего парой строк текста.
Помимо вышеупомянутых параметров, при размещении плавающих объектов используются длины
  1. \textfloatsep — расстояние между флоатс (в верхней или нижней части страницы) и текстом (по умолчанию, около 20pt);
  2. \floatsep — вертикальное расстояние между двумя флоатс (около 12pt);
  3. \intextsep — расстояние между флоатс вставленным "прямо здесь" (параметр h) и текстом (около 12pt);
  4. \abovecaptionskip и \belowcaptionskip — расстояние над и под подписью к флоат.
Их можно изменить, например, так
01:  \setlength{\textfloatsep}{10pt plus 1.0pt minus 2.0pt}
02:  \setlength{\floatsep}{5pt plus 1.0pt minus 1.0pt}
03:  \setlength{\intextsep}{5pt plus 1.0pt minus 1.0pt}
чтобы всунуть больше плавающих объектов на одну страницу.

Каковы последствия алгоритма? Прежде всего, [!h] означает вовсе не "здесь и только здесь", а "здесь, если оно поместится". Точно также, как [!htpb] и [pb!th] означают абсолютно одно и то же. То есть порядок символов, в том числе и вослицательного знака, никакой роли не играет.
Всё, выдыхаем... Дальше пойдут рецепты.

Здесь, здесь, здесь и только здесь.

Об этом уже писал в блоге virens, но повторюсь: параметр [H] всунет плавающий объект именно там, где он встречается в tex-файле. Если флоат не помещается, то будет начата новая страница, оставив, как результат, пустое место на предыдыщей. Не стоит использовать этот параметер без особой надобности. Ну, и не забудьте сначала сказать \usepackage{float}.

A вам нужны эти флоатс?

Вообще говоря, если вы хотите поместить картинку и её подпись "прямо здесь", то вовсе необязательно использовать плавающий объект. Команда \captionof{}{} из замечательного пакета caption позволяет снабдить подписью что угодно. Например, вот такой код
01:  {
02:  \centering
03:  \includegraphics{mypicture}
04:  \captionof{figure}{Подпись к картинке}\label{fig:mypic}
05:  }
вставит картинку и снабдит её подписью. Первый аргумент — тип плавающего объекта, в данном случае, figure, но с таким же успехом могло бы быть table, wrapfigure и т.п.

Пример использования \captionof

"А для чего оно нужно?", — спросишь ты, привередливый читатель. А, например, для вот такого:
01:  ...
02:  \usepackage{array,graphicx,caption}
03:  ...
04:  \begin{tabular}{m{0.45\linewidth}m{0.45\linewidth}}
05:       Here just some text text text text text text text 
06:       text text text text text text text text text
07:       text text text text text text text text text 
08:       text text text text text text text text text 
09:       text text text text text text text text text  
10:      &
11:       \centering
12:       \includegraphics{roman.jpg}
13:       \captionof{figure}{Usage of captionof}\label{fig:intab}
14:  \end{tabular}

Конечно, не стоит злоупотреблять \captionof: в вышеупомянутом примере гораздо лучшей альтернативой является wrapfigure. Более адекватным примером использования \captionof является случай, когда картинку и таблицу надо разместить так, чтобы они гарантированно были друг под другом, т.е. в пределах одного плавающего объекта:
01:  \begin{figure}\centering % В одном флоат...
02:    % сначала картинка...
03:    \includegraphics[width=7cm]{fig/roman_b}
04:    \captionof{figure}{Figure part of the float}\label{fig:fig}
05:  \vspace*{3em}
06:    % потом таблица
07:    \begin{tabular}{ccc}
08:      ...
09:    \end{tabular}
10:    \captionof{table}{Table part of the float}\label{fig:table}
11:  \end{figure}

Сложный пример с \captionof

Примечание: Нетерпеливый читатель может пропустить этот пример без ущерба для понимания последующего текста.
Во своей своей красе \captionof предстаёт в случаях, когда надо разместить несколько картинок в пределах одного плавающего объекта, как, например, на рисунке внизу.
Стоит обратить внимание на выравнивание картинок: (b) и (c) занимают по высоте ровно столько места сколько более высокая картинка (а) слева. Код из этого примера приведен ниже:
01:  ...
02:  \usepackage[labelformat=simple]{subcaption}
03:  % метка subfigure: "(а)" вместо дефолтного "а"
04:  \renewcommand\thesubfigure{(\alph{subfigure})} 
05:  \usepackage{graphicx}
06:  ...
07:  
08:  \newsavebox{\leftpic}
09:  
10:  \begin{figure}[t]\centering
11:  % Левая картинка (а) помещена в бокс, чтобы измерить её высоту
12:  \sbox{\leftpic}%
13:  {% Левая картинка (a):
14:   \begin{subfigure}[b]{0.45\linewidth}\centering
15:     \includegraphics[height=7cm]{fig/roman_a1}
16:     \caption{Subfigure A}\label{fig:2a}
17:   \end{subfigure}%
18:  }
19:   %------------------------
20:   % Вывeсти картинку, сохраненную в боксе
21:   \usebox{\leftpic}
22:   \quad % немного пустого места между левой и правой картинками
23:   % Две правые картинки в минипейдж, 
24:   %   - высота которого равна высоте левой картинки: \ht\leftpic
25:   %   - материал будет растянут вертикально: [s] + \vfill 
26:   \begin{minipage}[b][\ht\leftpic][s]{0.45\linewidth}
27:    \begin{center}
28:     \includegraphics[height=2.5cm]{fig/roman_b}
29:     \captionof{subfigure}{Subfigure B}\label{fig:2b}
30:    \end{center}
31:  
32:    \vfill
33:  
34:    \begin{center}
35:     \includegraphics[height=2.5cm]{fig/roman_c}
36:     \captionof{subfigure}{Subfigure C}\label{fig:2c}
37:    \end{center}
38:   \end{minipage}
39:  \caption{Fancy placement of subfigures}
40:  \label{fig:2}
41:  \end{figure}
Здесь используется пакет subcaption, в котором определено окружение subfigure: оно, по-сути, идентично окружению minipage. Усложняющим фактором является то, что высота левой картинки заранее неизвестна. Поэтому картинка (а) сначала помещена в savebox под именем \leftpic при помощи команды \sbox{\leftpic}. Затем, после того как она выведена на печать с помощью \usebox{}, справа создаётся minipage:
01:  \begin{minipage}[b][\ht\leftpic][s]{0.45\linewidth}
высота которой равна высоте левой картинки (а): \ht\leftpic. Обратите внимание на необязательный аргумент [s] (s=stretch) и \vfill между (b) и (c). Благодаря им между (b) и (c) помещается "растягивающийся вертикальный интервал" таким образом, что картинки (b) и (c) полностью занимают всю высоту minipage.
В приведенном примере \captionof незаменим, так как он снабжает рисунки (b) и (c) подписью, причем делает это не абы как, а именно так как подписаны все другие subfigure и к тому же инкрементирует все необходимые счётчики, т.е. нумерация (b) и (c) получается автоматически.
В качестве домашнего задания, попробуйте соорудить вот такие две картинки.

Код для левой картинки:открыть
01:  ...
02:  \usepackage[labelformat=simple]{subcaption}
03:  \renewcommand\thesubfigure{(\alph{subfigure})} % I want (a), not just a
04:  
05:  \usepackage[demo]{graphicx} % опция demo вставляет черные прамоугольники вместо картинок
06:  ...
07:  \begin{figure}[!t]\centering
08:  \setcounter{subfigure}{0}
09:  \addtocounter{figure}{1}
10:  \def\hgt{15cm}
11:  \def\wdt{5cm}
12:   \begin{minipage}[b][\hgt][s]{0.45\linewidth}
13:    \begin{center}
14:     \includegraphics[width=\wdt]{fig/roman_b}
15:     \captionof{subfigure}{Subfigure A}\label{fig:3a}
16:    \end{center}
17:  
18:    \vfill
19:  
20:    \begin{center}
21:     \includegraphics[width=\wdt]{fig/roman_c}
22:     \captionof{subfigure}{Subfigure B}\label{fig:3bb}
23:    \end{center}
24:  
25:     \vfill
26:  
27:    \begin{center}
28:     \includegraphics[width=\wdt]{fig/roman_aa}
29:     \captionof{subfigure}{Subfigure C}\label{fig:3c}
30:    \end{center}
31:   \end{minipage}
32:  %
33:   \quad
34:  %
35:   \begin{minipage}[b][\hgt][s]{0.45\linewidth}
36:    \begin{center}
37:     \includegraphics[angle=90,width=\wdt]{fig/roman_b}
38:     \captionof{subfigure}{Subfigure D}\label{fig:3d}
39:    \end{center}
40:  
41:    \vfill
42:  
43:    \begin{center}
44:     \includegraphics[width=7cm,height=5cm]{fig/roman_c}
45:     \captionof{subfigure}{Subfigure E}\label{fig:3e}
46:    \end{center}
47:   \end{minipage}
48:   \addtocounter{figure}{-1}
49:   \caption{Fancy placement of subfigures}\label{fig:3}
50:  \end{figure}

Код для правой картинки:открыть
01:  ...
02:  \usepackage{caption}
03:  \usepackage[demo]{graphicx} % опция demo вставляет черные прямоугольники вместо картинок
04:  ...
05:  \begin{figure}[!t]\centering
06:  \def\hgt{15cm}
07:  \def\wdt{5cm}
08:   \begin{minipage}[b][\hgt][s]{0.45\linewidth}
09:    \begin{center}
10:     \includegraphics[width=\wdt]{fig/roman_b}
11:     \captionof{figure}{caption x1}\label{fig:x1}
12:    \end{center}
13:  
14:    \vfill
15:  
16:    \begin{center}
17:     \includegraphics[width=\wdt]{fig/roman_c}
18:     \captionof{figure}{caption x2}\label{fig:x2}
19:    \end{center}
20:  
21:     \vfill
22:  
23:    \begin{center}
24:     \includegraphics[width=\wdt]{fig/roman_aa}
25:     \captionof{figure}{caption x3}\label{fig:x3}
26:    \end{center}
27:   \end{minipage}
28:  %
29:   \quad
30:  %
31:   \begin{minipage}[b][\hgt][s]{0.45\linewidth}
32:    \begin{center}
33:     \includegraphics[angle=90,width=\wdt]{fig/roman_b}
34:     \captionof{figure}{caption x4}\label{fig:x4}
35:    \end{center}
36:  
37:    \vfill
38:  
39:    \begin{center}
40:     \includegraphics[width=7cm,height=5cm]{fig/roman_c}
41:     \captionof{figure}{caption x5}\label{fig:x5}
42:    \end{center}
43:   \end{minipage}
44:  %
45:  \end{figure}

Код из этих и всех остальных примеров (в виде полностью готовых к компиляции tex-файлов) можно также найти по этой ссылке: http://tinyurl.com/amorua-floats.

До сюда и ни миллиметром дальше: placeins

Вернёмся, однако, к основной теме: к дополнительным средствам контроля над расположением плавающих объектов. В некоторых ситуациях, нежелательно, чтобы плавающие объекты переносились слишком далеко. Например, нелогично, когда картинка из предыдущего раздела возникает лишь в следующем.
Штатным решением этой проблемы является \clearpage, который принудительно разгружает очередь плавающих объектов и начинает новую страницу. Последнее — новая страница — не всегда приводит к красивому результаты. Зачастую хотелось бы вывести все плавающие объекты без начала новой страницы, если это возможно.
Пакет placeins определяет команду \FloarBarrier, которая решает именно вышеупомянутую проблему. Как только LaТeX встретит \FloatBarrier, он выведет все накопившиеся в очереди флоатс, но при этом не будет без надобности начинать новую страницу.
Зачастую, начало нового раздела \section{} и является той логической границей, которую плавающие объекты не должны пересекать. Можно, конечно, вручную указывать \FloatBarrier перед каждым \section. Однако пакет placeins предоставляет опцию section, которая сделает это автоматически:
01:  \usepackage[section,above,below]{placeins}
Здесь использованы ещё две опции above и below. Они разрешают вывод картинки на той же странице, где начинается новый раздел (над или под названием раздела), хотя картинка относится к предыдущему. В некоторых случаях, \FloatBarrier всё-таки приведет к неприятным разрывам страниц. Типичная ситуация такого рода: флоат не влезает на остаток страницы, а после него сразу идёт \FloatBarrier. Здесь у ЛаТеХа не остаётся выбора и будет начата новая страница. Предотвратить такое поведение можно с помощью команды \afterpage из одноименного пакета
01:  ...
02:  \usepackage{afterpage,placeins}
03:  ...
04:  \begin{figure} % здесь сам флоат
05:    ...
06:  \end{figure}  
07:  
08:  \afterpage{\FloatBarrier} % вставить барьер сразу после
09:                            % начала новой страницы
10:  ...
Эта команда вставляет свой аргумент в TeX-код сразу после начала новой страницы.

Утром деньги — вечером стулья: flafter

Одним из последствий алгоритма, описанного в самом начале этого поста, может быть то, что даже если в tex-файле плавающий объект идет после первой ссылки на него, "на бумаге" он окажется раньше, чем на него первый раз ссылаются. Если этого желательно избежать, то самым простым решением является пакет flafter.
01:  \usepackage{flafter}% помещает флоат ПОСЛЕ первой ссылки на него 
Вот, собственно, и всё!

Да ну их всех взад: endfloat

Многие естественнонаучные журналы требуют, чтобы в манускриптах, посланных им на рецензию, все рисунки были вынесены в самый конец. Пакет endfloat сделает это автоматически: он перенесёт все рисунки в конец документа.
По умолчанию, пакет вставит на место рисунков и таблиц (в основном тексте) заглушки типа "[Figure 5 about here]". Затем, после основного текста, сначала Список рисунков и Список таблиц, а затем и сами рисунки/таблицы, центрированными по одной на странице.
Контролировать поведение пакета можно с помощью параметров, наиболее интересными из которых являются nomarkers, nofiglist и notablist. Например,
01:  \usepackage[nomarkers,nofiglist,notablist]{endfloat}
не будет вставлять заглушки и списки рисунков и таблиц.
Если списки флоатс все-таки нужны, то порядок их вывода контролируется параметром tablesfirst или figuresfirst (включен по умолчанию), которые, выводят первым список таблиц или рисунков, соответственно.

Картинки с продолжением: \ContinuedFloat

Иногда возникает необходимость разместить большое количество логически связанных "подрисунков" (subfigures) в пределах одного рисунка. Однако, ЛаТеХ не поддерживает плавающие объекты размером более одной страницы. Проблема решается командой \ContinuedFloat из уже упомянутого пакета caption. Использование этой команды очевидно из примера ниже:
01:  ...
02:  \usepackage{caption}
03:  \usepackage[labelformat=simple]{subcaption}
04:  \renewcommand\thesubfigure{(\alph{subfigure})} % I want (a), not just a
05:  ...
06:  \begin{figure} % Начало "длинного" рисунка
07:    \begin{subfigure}{0.5\linewidth}  % Первый "подрисунок"
08:       \includegraphics{...}
09:       \caption{...}\label{...}
10:    \end{subfigure}
11:    ... % здесь ещё подрисунки
12:    \begin{subfigure}{0.5\linewidth}  % n-й "подрисунок
13:       \includegraphics{...}
14:       \caption{...}\label{...}
15:    \end{subfigure}
16:    \caption{Мой любимый рисунок}\label{...}
17:  \end{figure} % конец первой части
18:  
19:  \begin{figure} \ContinuedFloat % продолжение рисунка
20:    \begin{subfigure}{0.5\linewidth}  % (n+1)-й "подрисунок"
21:       \includegraphics{...}
22:       \caption{...}\label{...}
23:    \end{subfigure}
24:    ... % здесь ещё подрисунки
25:    \begin{subfigure}{0.5\linewidth}  % последний "подрисунок
26:       \includegraphics{...} 
27:       \caption{...}\label{...}
28:    \end{subfigure}
29:    \caption{Мой любимый рисунок (продолжение)} % \label здесь не нужна!!! 
30:  \end{figure} % конец второй (и последней) части рисунка
Принцип очень прост: делим "длинный рисунок" на несколько частей. Каждую часть помещаем в отдельный плавающий объект (окружение figure). Во всех частях, кроме первой добавляем \ContinuedFloat сразу после \begin{figure}. Эта команда "переставит" все счётчики (для figure и для subfigure) соответствующим образом: figure не изменяется (все части имеют один "номер"), а subfigure продолжится начиная с последней буквы предыдущей части.
Обратите внимание, что к каждой части надо вручную добавить \caption{...}.
Абсолютно то же самое можно проделать для любого типа плавающего объекта, например, для table.

Картинки на развороте: dpfloat

Если два больших флоат-рисунка связаны логически, как, например, в примере из предыдущего раздела, то их желательно разместить так, чтобы читатель мог лицезреть обе части одновременно, то есть на развороте. Это особенно удобно, если текст манускрипта будет напечатан в виде книжки: например, в случае диссертации.
На практике это означает, что первая часть рисунка должна попасть на чётную страницу, а вторая — на нечётную (предполагается, что книжка начинается со страницы 1, у которой нет "разворотной пары"). Сделать это можно с помощью пакета dpfloat. Ограничением является то, что каждая из частей будет занимать полную страницу, на которой не будет текста. А делается это так: надо создать два плавающих объекта, идущих в tex-файле друг за другом. Рисунок внутри первого флоат, который должен оказаться слева, помещается внутрь окружения leftfullpage, а рисунок внутри второго, который предполагается быть на правом развороте, внутрь fullpage. Пример ниже демонстрирует это в подробностях.
01:  ...
02:  \usepackage{dpfloat}
03:  ...
04:  \begin{figure} % первая часть
05:    \begin{leftfullpage} % Эта картинка гарантированно окажется
06:                         % на ЛЕВОМ развороте
07:       % здесь все, что обычно...
08:       % например, \includegraphics{...}
09:    \end{leftfullpage}
10:  \end{figure}
11:  
12:  \begin{figure} % вторая часть
13:    \begin{fullpage} % Эта картинка гарантированно окажется
14:                     % на ПРАВОМ развороте
15:       % здесь все, что обычно...
16:       % например, \includegraphics{...}
17:    \end{fullpage}
18:  \end{figure}

Последний рецепт: одинокие картинки

Несмотря на все продвинутые способы контроля положения плавающих объектов, время от времени возникают ситуации, когда посленяя (или пара последних) картинка остаётся напоследок и оказывается одиноко на самой последней странице. При этом, независимо от параметров вроде [hbt], она будет размещена (вертикально) по центру страницы. Но зачастую желательно разместить картинку вверху страницы, в основном, из эстических соображений. Достичь этого очень просто, поместив следующий код в tex-файл:
01:  \makeatletter
02:  \setlength{\@fptop}{0pt}
03:  \setlength{\@fpbot}{0pt plus 1fil}
04:  \makeatother
Любознательные могут ознакомиться с подробностями вот здесь.

Заключение и выводы

Итак, штатные средства ЛаТеХ позволяют контролировать местоположение плавающих объектов с помощью необязательных аргументов [htbp!] и параметров определяющих максимальное количество таких объектов на странице и её частях. Для более продвинутого контроля можно использовать расширения, содержащиеся в пакетах float, caption, placeins, afterpage, flafter, endfloat и dpfloat. В этом посту мы обсудили наиболее общеупотребительные их аспекты, однако для более подробного описания лучше ознакомиться с оригинальной документацией.
Прибегнув к "тонкой настройке" плавающих объектов, в большинстве случаев можно добиться вполне приемлемых результатов даже при "автоматическом" размещении их ЛаТеХом. Разумеется, при диспропорционально большом количестве рисунков и/или таблиц, скорее всего понадобится ручное вмешательство.
При возникновении конкретных проблем, зачастую быстрее всего получить ответ можно задав вопрос на http://tex.stackexchange.com/.
Исходники (tex-файлы) для всех примеров из данного поста можно найти здесь. Зеркала на случай сбоя: зеркало1, зеркало2
Читать далее

Вглубь синтетических джунглей файловой системы sysfs в Linux



8 коммент.
Файловая система /sys в Linux отличается от /proc тем, что предоставляет детализированную информацию о работе ядра пользователю (например, параметры устройств и загруженных модулей). Информация строго организована и обычно форматируются простом ASCII тексте, что делает её очень доступной для пользователей и приложений. Так что можно занять шаловливые ручонки чем-нибудь полезным, вроде дёргания разных крутилок в /sys и подсматриванием в системные переменные. Далее - немного подробностей о синтетических джунглях файловой системы /sys.


Зачем нужна /sys, когда есть /proc? 

Основной лейтмотив создания /sys было навести некоторый порядок в том бардаке, который являет из себя /proc и выделить информацию о структурах ядра в отдельную директорию.

Sysfs это
файловая система, находящаяся в памяти (in-memory), основана первоначально на Ramfs, которая в свою очередь была написана во время перехода на ядро 2.4.0. Как говорит один из авторов [1], ``это было упражнение в элегантности, имевшее целью показать, насколько легко написать простую файловую систему, если использовать новый на тот момент слой VFS''. Из-за простоты и использования VFS, это дало здоровую основу для создания других in-memory файловых систем.

При этом sysfs может быть смонтирована, как и любая другая файловая система из пространства пользователя. Большинство дистрибутивов делают это автоматически при старте системы, добавляя соотвутствующую строчку в /etc/fstab.


Что внутри /sys?
Sysfs является каналом распространения информации между ядром и пространством пользователя. Например, есть возможность смены планировщика ввода/вывода или изменения параметров Udev программы. В каталоге /sys находится несколько подкаталогов, представляющих ряд основных подсистем, которые зарегистрированы в Sysfs:
/sys/
|-- block
|-- bus
|-- class
|-- devices
|-- firmware
|-- module
‘-- power


Внутри
/sys/block
Каталог /sys/block содержит подкаталоги для каждого блочного устройства, которое было обнаружено в системе. Там хранятся параметры, которые описывают такие свойства блочных устройств, как размер устройства, его партиции, планировщик ввода-вывода и другие.

Зайдя туда, мы обнаруживаем кучу блочных устройств, среди которых можно найти рабочий винчестер, подключённые флешки и внешние жёсткие диски. Вот что автор этих строк нашёл про свой жёсткий диск, на котором установлен евонный Дебиан:

notebeast:/sys/block/hda# ls -l
итого 0
-r--r--r-- 1 root root 4096 2012-03-03 22:05 capability
-r--r--r-- 1 root root 4096 2012-03-03 22:05 dev
lrwxrwxrwx 1 root root 0 2012-03-03 22:05 device -> ../../devices/pci0000:00/0000:00:1f.1/ide0/0.0
drwxr-xr-x 3 root root 0 2012-03-03 22:05 hda1
drwxr-xr-x 3 root root 0 2012-03-03 22:05 hda2
drwxr-xr-x 2 root root 0 2012-03-03 18:40 holders
drwxr-xr-x 3 root root 0 2012-03-03 22:05 queue
-r--r--r-- 1 root root 4096 2012-03-03 22:05 range
-r--r--r-- 1 root root 4096 2012-03-03 22:05 removable
-r--r--r-- 1 root root 4096 2012-03-03 22:05 size
drwxr-xr-x 2 root root 0 2012-03-03 18:40 slaves
-r--r--r-- 1 root root 4096 2012-03-03 22:05 stat
lrwxrwxrwx 1 root root 0 2012-03-03 22:05 subsystem -> ../../block
--w------- 1 root root 4096 2012-03-03 22:05 uevent
Отсюда мы узнаём, например, что диск /dev/hda разбит на две партиции, hda1 и hda2, размеры которых хранятся в size, что можно достучаться до планировщика I/O в queue   и собрать немножко статистики по работе жёсткого диска в stat. Заглянем туда в поисках приключений и чего-нибудь неизведанного.


Статистика ввода-вывода

Интерфейс /sys/block/sdX/stat даёт некоторые статистические данные о производительности ввода-вывода ядра. Эти данные пользователь или администратор может использовать для оптимизации производительности, если знает, что они значат.

Например, если дать команду:

# cat /sys/block/sda/stat
Мы увидим что-то типа:

186908 41568 6033917 2408504 91198 509600 4882200 9406764 0 1161304 11848624

Эти сакрально-литургические знаки означают следующее:

Поле 1 -- полное число запросов на чтение, выполненных успешно.


Поле 2 -- число объединённых запросов на чтение. Запросы на чтение и запись, примыкающие друг к другу, могут быть объединены для повышения эффективности. Таким образом, два 4K считывания может стать одним 8K считыванием перед тем, как в конечном итоге быть переданы диску. Поэтому запрос будет считаться одним, и это поле позволяет вам узнать, как часто это было сделано.

Поле 3 -- число считанных секторов, чтение которых прошло успешно. 

Поле 4 -- миллисекунд, потраченных на чтение. 

Поле 5 -- число запросов на запись, выполенных успешно.

Поле 6 -- число объединённых запросов на запись. Запросы на чтение и запись, примыкающие друг к другу, могут быть объединены для повышения эффективности. Таким образом, два 4K считывания может стать одним 8K считыванием перед тем, как в конечном итоге быть переданы диску. Поэтому запрос будет считаться одним, и это поле позволяет вам узнать, как часто это было сделано.

Поле 7 -- число секторов, записанных успешно.

Поле 8 -- миллисекунды, потраченные на запись.

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

 Поле 10 -- миллисекунд, потраченных на выполнение запросов ввода-вывода. 

Поле 11 -- взвешенное количество миллисекунд, потраченных на ввод-вывод. Может использоваться как простая мера производительности ввода-вывода.




Смена планировщика ввода-вывода на лету

Как нам намекает документация, планировщик ввода-вывода может быть изменён в любое время на лету, хотя может быть небольшая задержка из-за того, что все запросы предыдущего планировщика должны быть обработаны прежде, чем запустится новый. Чтобы узнать, какой планировщик стоит сейчас, даём команду:
cat /sys/block/sdX/queue/scheduler
Заменяя sdX на интересующее нас устройство. Текущий планировщик отмечен в квадратных скобках:
noop anticipatory deadline [cfq]
То есть сейчас стоит cfq - Completely Fair Queuing, полностью честный планировщик. Планировщики для разных дисков могут быть:
  • noop часто наилучший выбор для файловых систем в памяти (например ramdisk) и других устройств без механических частей (флешек), где попытки оптимизировать ввод-вывод приводят лишь к напрасной трате ресурсов.
  • as (anticipatory) по воплощённым в нём идеях схож с deadline, но более навороченный и пытается оптимизировать ввод-вывод с упреждением. Удалён из ядер начиная с 2.6.33.
  • deadline лёгкий планировщик, который пытается установить жёсткий предел на задержки ввода-вывода.
  • cfq поддерживает честное распределение ввода-вывода между процессами, используя концепцию очередей (queue) для каждого процесса. CFQ разедляет синхронные и асинхронные операции ввода-вывода, отдавая предпочтение синхронным операциям. Грубо говоря, CFQ не допускает ситуации, когда один процесс начнёт создавать много операций ввода-вывода, другие процессы могут ``голодать''. Имеет несколько параметров настройки.
Выбор планировщика зависит от задач и оборудования (любопытные бенчмарки для SSD). Более того, у каждого планировщика, как правило, есть настраиваемые параметры. Некоторые соображения можно почерпнуть из поста по ссылке.

Сменить планировщик можно на лету:
# echo "deadline" > /sys/block/sda/queue/scheduler
После этого планировщик для данного диска будет изменён. 
 


И другие каталоги...
 Содержимое других каталогов будет интереснее разработчикам, а не пользователям, и может сильно меняться от версии ядра Linux.

/sys/bus
Это структура шин данных в системе, которая показывает, какая шина куда подключена (например, контроллер USB может быть подключен к шине PCI), и какие устройства в каждой шине потенциально может поддерживать (наряду с соответствующими драйверами), и какие устройства существуют. Здесь есть символической ссылки, которые указывают на директории устройства в глобальном дереве устройств. Каждый тип шины данных представлен двумя подкаталогами: устройств и драйверов.
   
/sys/class
Хранит все классы устройств, зарегистрированные ядром. Используется для описания функционального типа устройств. Большинство подкаталогов содержат символические ссылки на каталоги device и driver. Например, физическое устройство типа мышь может ссылаться на объект ядра "мышь", на устройство input event и input debug. Классы могут включать в себя диски, разделы, последовательные порты, и т.д.  

/sys/devices
Содержит глобальную иерархию устройств: каждое физическое устройство, которые было обнаружено и зарегистрировано ядром.

Например, автор этих строк нашёл:
/sys/devices/virtual/thermal/thermal_zone0/temp  
показания температуры на процессоре в ноутбуке. Исключений два - platform devices и system devices.

Platform devices это периферия (подключаемые устройства), присущие конкретной платформе (порты ввода-вывода, legacy-устройства типа последовательного контроллера или контроллера дискет [floppy controller]).

System devices это устройства, интергрированные в платформу, например аппаратные регистры для доступа к конфигурированию, которые не имеют возможностей обмениваться данными. Обычно для них нет драйверов (процессор, таймеры и другое).
   
/sys/firmware
Cодержит интерфейсы для просмотра и манипулирования firmware-специфичными объектами и их параметрами. Как правило, это платформо-зависимый код, который выполняется в системе при включении, например BIOS.  

/sys/module
Cодержит подкаталоги для каждого загруженного модуля ядра. Имя каталога отражает имя модуля. Ядро имеет глобальное пространство имён для всех модулей. Подкаталоги содержат параметры, специфичные для каждого загруженного модуля. Эта информация используется для отладки и простым смертным не будет интересна.  

/sys/power
Это скорее заделка на будущее. Может содержать название состояния, которое позволит процессу переходить в режим пониженного энергопотребления.
В зависимости от версии ядра, в /sys могут появляться и другие каталоги.


Ссылки
Есть любопытный документец [1] The sysfs Filesystem, OLS'05 на 14 страниц, написанная тем водянистым и пустозвонным стилем, коий так не переваривает автор этих строк. Документация к ядру тоже не особенно жаждет подробно рассказать о том, что означают все эти переменные и отгораживается вот этим:

TODO: Finish this section.
Понятно, что это самое туду не входит в приоритетный список дел. Но кое-что выудить всё-таки можно. Надеюсь, что этот пост несколько приподымет завесу тайны с файловой системы /sys.
Читать далее

Обзор редакторов для работы в ЛаТеХ: LaTeX Editors and Integrated LaTeX Environments



24 коммент.

Частый вопрос начинающих латехников: ну вот установили мы LaTeX, а как теперь со всем этим работать? Вопрос задают сравнительно часто, и подумалось мне, что неплохо бы всё это оформить в виде одного поста со скриншотами и сравнениями. Описание сред для работы с LaTeX идёт в порядке убывания возможностей программ.

Читать далее

Xournal - рукописные заметки и пометки в PDF файлах



9 коммент.

Наличие у вас графического планшета или ноутбука с экраном, чувствительным к нажатию, открывает широкие возможности для творчества: можно рисовать картины (почти как на бумаге), создавать чертежи в CAD-программах (планшет сильно облегчит работу) или делать рукописные заметки.

Читать далее

Продвинутые таблицы в ЛаТеХе: advanced tables in LaTeX



30 коммент.

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

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

Объединение строк и столбцов в таблицах LaTeX

Создание навороченных таблиц часто требует объединять столбцы и строки, особенно при группировке сходных данных. Для этого можно использовать команды \multicolumn и \multirow, а так же некоторые другие трюки, о которых ниже.

Напомню, что \multicolumn{2}{|c|}{Результаты измерений} означает, что мы объединяем 2 (два) столбца в таблице, получившаяся ячейка будет центрирована и нарисованы вертикальные линии.

Таблицы с объединением столбцов в LaTeX

Для того, чтобы несколько столбцов объединить в одну, можно воспользоваться командами \cline, \raisebox и \multicolumn одновременно. Здесь \multicolumn служит для объединения двух колонок в одну, \cline прочерчивает линию в строках, а \raisebox поднимает текст к середине объединённой строки.
Вот код таблицы:

\begin{table}[H]
\caption{\label{tab:bolts} Нестандартные болты для левой резьбы.}
\begin{center}
\begin{tabular}{|c|c|c|}
\hline
& \multicolumn{2}{c|}{Диаметр} \\
\cline{2-3}
\raisebox{1.5ex}[0cm][0cm]{Нестандартные болты}
& Норма & Разброс \\
\hline
Размеры & 10 мм & 1 мм \\
\hline
\end{tabular}
\end{center}
\end{table}

В документе это будет выглядеть так (обратите внимание на первую колонку):


Для этой таблицы использован трюк с \multicolumn для объединения двух ячеек в одну, \cline{2-3} для прочерчивания горизонтальной линии в таблице от второй колонки до третьей, и \raisebox для вставки надписи Нестандартные болты.


Таблицы с объединением строк в LaTeX

Если нужна таблица, в которой несколько строк объединены, можно использовать пакет multirow, добавив \usepackage{multirow} в преамбулу документа. Это позволит создать строки, простирающиеся на несколько колонок командой:
\multirow{объединить Х строк}{ширина}{содержимое}
Предыдущий пример можно переиначить вот так:

\begin{table}[H]
\caption{\label{tab:bolts} Нестандартные болты для левой резьбы.}
\begin{center}
\begin{tabular}{|c|c|c|}
\hline
\multirow{3}{*}{Размеры нестандартных болтов} & \multicolumn{2}{c|}{Диаметр} \\
\cline{2-3}
            & Норма & Разброс \\
\cline{2-3}
            & 10 мм & 1 мм \\
\hline
\end{tabular}
\end{center}
\end{table}

В документе такая таблица будет выглядеть так:



Объединение строк и столбцов вместе плюс использование hhline

Пример с texexchange, который мне нравится, иллюстрирует применение описанных выше команд:

\begin{table}[ph]
  \centering
  \begin{tabular}{c|c|c|c|c}
    \hline
    \multirow{2}{*}{Raaa (k)} & \multicolumn{4}{c}{C ()} \\
    \hhline{~----}
    & 3.3 & 2.5 & 1 & 0.5 \\
    \hline
    \multirow{2}{*}{Raaa (k)} & \multicolumn{2}{c|}{\multirow{2}{*}{this}} & 0.5 & 0.6\\
    \hhline{~~~--}            & \multicolumn{2}{c|}{}                      & 0.7 & 1.2 \\
    \hline
  \end{tabular}
  \caption{R, C ripple size}
  \label{T:peak}
\end{table}

В документе выглядит так:


Здесь нужно отметить применение команды \hhline из одноимённого пакета hhline, которая рисует линии в таблицах, подобно обычной \hline. Особенность \hhline в том, что можно прочерчивать невидимые линии (~) и обычные (-) вот так:
\hhline{~----}
В данном случае будет нарисовано пять линий в таблице, первая будет пустая. В общем это аналог \cline{2-5}, только более удобный.

Надеюсь, что с такими таблицами вы будете встречаться так же редко, как и с такими экзотическими болтами.


Раскраска ячеек таблиц в LaTeX

Кто сказал, что таблицы в LaTeX унылы и безжизненны? Хотя часто раскраска таблицы не одобряется, иногда, особенно в презентациях, выделение ячеек таблицы цветом помогает быстрее понять материал.
Для раскраски ячеек нам понадобятся пакеты
\usepackage{color,colortbl}
и в преамбуле определяем цвета, которые нам нужны:
\definecolor{darkishgreen}{RGB}{39,203,22}
\definecolor{LightCyan}{rgb}{0.88,1,1}
\definecolor{Gray}{gray}{0.9}
\definecolor{lightRed}{RGB}{230,170,150}
\definecolor{modRed}{RGB}{230,82,90}
\definecolor{strongRed}{RGB}{230,6,6}
Теперь нужно сделать отдельный тип цветных колонок для таблицы. Для этого в документе, уже после \begin{document}, создаём новые команды в виде:
\newcolumntype{g}{>{\columncolor{Gray}}c}
и
\newcolumntype{d}{>{\columncolor{darkishgreen}}c}
Это позволит нам раскрашивать колонки. Для раскраски строк воспользуемся командой \rowcolor{цвет} из пакета colortbl. Можно раскрасить отдельно ячейку с помощью команды \cellcolor{Gray} которую помещаем в раскрашиваемую ячейку.

А теперь всё вместе:

\newcolumntype{g}{>{\columncolor{Gray}}c}
\newcolumntype{d}{>{\columncolor{darkishgreen}}c}

\begin{tabular}{|c||c||g||d|d|d|}
    \hline
 Signal & \cellcolor{Gray} Device    & \multicolumn{4}{|c|}{Computation time, s}\\
\cline{3-6}
Strength    & \cellcolor{Gray}  size     &Dantzig-   &Branch and & Active    &Projected\\ 
        &       &Wolfe      &Bound      &Set        &Gradients\\ 
\rowcolor{lightRed}
\hline
Weak        & 7x7   &400        &230        &200        &58\\ \cline{3-6}
\rowcolor{lightRed}
(0\% constr.)    & 10x10 &1000       &840        &500        &135 \\ \cline{3-6}

\hline
\rowcolor{modRed}
Moderate    & 7x7   &640        &380        &270        &54\\ \cline{3-6}
\rowcolor{modRed}
(5\% constr.)    & 10x10 &3120       &1200       &700        &110 \\ \cline{3-6}

\hline
\rowcolor{strongRed}
Strong      & 7x7   &1400       &290        &350        &55\\  \cline{3-6}
\rowcolor{strongRed}
(20\% constr.)   & 10x10 &15320      &810        &960        &120 \\  \cline{3-6}
\hline \hline
    \end{tabular}

В документе такая таблица выглядит вот так:


Здесь ещё можно отметить использование || в качестве двойного разделителя колонок.




Изменение размеров строк и столбцов в ЛаТеХ таблице

Переменная \arraystretch отвечает за расстояние между строками а переменная \tabcolsep соответственно за расстояние между столбцами. В примере ниже мы сделаем столбцы и строки пошире:

\renewcommand{\arraystretch}{1.8} %% increase table row spacing
\renewcommand{\tabcolsep}{1cm}   %% increase table column spacing
\begin{center}
\begin{tabular}{|c|c|c|}
\hline
Расширение краёв: & \textbf{1,0-1,4} & размер ФРТ \\
\hline
Аподизация: & \textbf{0,25-0,30} & размер ФРТ \\ 
\hline
Сглаживания краёв: & \textbf{0,25-0,50}& размер ФРТ \\
\hline
\end{tabular}
\end{center}

В документе это будет выглядеть так:



Изменение высоты одной строки в таблице

Иногда требуется сделать одну из строк в таблице побольше, не задевая все остальные. Здесь поможет трюк с командой rule: команда вставит невидимую горизонтальную линию заданной ширины и толщины:
\rule[высота подъёма линейки]{ширина}{толщина}
Это не единственный манёвр, который позволяет увеличить расстояние между строками: можно в конце строки, после \\ вставить [1cm], увеличив размер строки соответственно.

В данном примере мы расширим первую строку в таблице с помощью \rule{0cm}{2cm} и вторую с помощью [1cm] следующим образом:

\begin{center}
\begin{tabular}{|c|c|c|}
\hline
\rule{0cm}{2cm}
Расширение краёв: & \textbf{1,0-1,4} & размер ФРТ \\
\hline
Аподизация: & \textbf{0,25-0,30} & размер ФРТ \\  [1cm]
\hline
Сглаживания краёв: & \textbf{0,25-0,50}& размер ФРТ \\
\hline
\end{tabular}
\end{center}
 
Так выглядит таблица в документе:


Ещё немного о трюках с таблицами можно почерпнуть там.




Книжные таблицы в LaTeX: booktabs

По умолчанию таблицы, набранные в латехе, смотрятся неплохо, хотя им недостаёт "книжного" вида. Например, первая и последняя линия в таблице обычно жирнее, чтобы показать начало и конец таблицы.

Если вам хочется набирать таблицы "как у больших дядь в книжках", можно воспользоваться пакетом booktabs. Подключив в преамбуле документа \usepackage{booktabs} мы сразу же имеем возможность набирать красивые таблицы.
"Большие дяди" стараются сделать таблицы проще, с комфортным для глаз расстояниями между строками, и почти никогда не используют вертикальные разделители.
Вот код для такой таблицы:

\begin{tabular}{llr}
\toprule     %%% верхняя линейка
\multicolumn{2}{c}{Постобработка} \
\cmidrule(r){1-2}
Вид & Описание & Время выполнения, сек. \
\midrule %%% тонкий разделитель 
Расширение краёв        & холодный старт & 12 \
                    & горячий старт &    8 \
Аподизация          & симметричная  & 90 \
Сглаживания краёв   & по Гауссу  & 33 \
\bottomrule %%% верхняя линейка
\end{tabular}
 
Вот как выглядит такая таблица:




Когда столбцов в таблице слишком много...

Чтобы проще было задавать число колонок таблицы, особенно если их много, можно использовать конструкцию вида \begin{tabular}{l*{X}{l}}, где X это число колонок.

Вот пример такой таблицы с 10 колонками:

\begin{tabular}{l*{10}{l}}
\hline
Расширение краёв:   &  1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\hline
Аподизация:             & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \\
\hline
Сглаживания краёв:  & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9  \\
\hline
\end{tabular}

А вот как она выглядит в готовом документе:


Стоит отметить пакет siunitx, который предоставляет возможность  выравнивания по десятичной точке или запятой. Также можно посмотреть на пакет array, предоставляющий расширенные версии окружений tabular и array (например, вертикально центрированные колонки и возможность определять новые типы колонок).


Ссылки

Эти трюки позволят создать весьма навороченные таблицы без необходимости перечитывать томик квантовой физики.

Конечно, есть ещё много пакетов по работе с таблицами, например ltxtable - это longtable и tabularx, который стоит использовать для создания больших и сложных таблиц с разделением по страницам, с кучей текста в ячейках. Многостраничные таблицы так же может создавать пакет supertab.

Cтоит упомянуть пакет slashbox, который позволяет создавать ячейки, разделенные по диагонали.

Стоит ещё отметить хороший туториал по таблицам, который включает \multirow и \multicol. Поборники русского стиля оформления таблиц могут заинтересоваться постом по ссылке.
Читать далее