Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > Асинхронный вывод - достижимо ли ускорение


Автор: marcusmae 24.1.2008, 15:20
Всем привет,

Изучаю, как можно было бы занять процессор полезной работой в то немаленькое число тактов, в которое он "занят" ожиданием появления результата на контроллере шины IDE.

В стандарте Linux существует пакет POSIX AIO (asyncronious i/o), в котором есть функции aio_read и aio_write. Особенность в том, что возврат из них происходит сразу же после вызова, без ожидания результата операции, отложенная обработка которого может быть осуществлена по сигналу.

На этот счёт вопрос : достижимо ли хоть какое-то ускорение работы приложения при использовании асинхронного вывода вместо обычного?

Из тех тестов, что я провёл следует, что нет, не достижимо. Но, во-первых, я мог где-то и наляпать smile (http://www-128.ibm.com/developerworks/linux/library/l-async/?ca=dgr-lnxw02aUsingPOISIXAIOAPI описано примерно то, что я делаю), а, во-вторых, интересно, что же у этой "асинхронности" под капотом? Если она сводится к созданию потока/контекста, в котором идёт обычный ввод/вывод, то это, конечно, ерунда. Но в таком случае странно, что эту технологию любят применять в realtime-системах.

Автор: GrayCardinal 24.1.2008, 18:07
Цитата

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

Именно так. Тупо создаётся новый поток. Только в Linux'е. В других ОС, к примеру FreeBSD, на сколько знаю - сделано всё как надо...

Автор: marcusmae 24.1.2008, 18:41
Цитата(GrayCardinal @  24.1.2008,  18:07 Найти цитируемый пост)
Именно так. Тупо создаётся новый поток. Только в Linux'е. В других ОС, к примеру FreeBSD, на сколько знаю - сделано всё как надо...


GrayCardinal, спасибо за ответ! = Хм, интересно, выходит, на разных системах разная реализация POSIX AIO API? В таком случае, я попробую поставить к себе в VMWARE какой-нибудь FreeBSD и провести тесты там...

Автор: GrayCardinal 24.1.2008, 20:04
Ещё хочу добавить, что в NetBSD, OpenBSD aio_ отсутствует...
http://nixdoc.net/man-pages/FreeBSD/?cmst=&cmsct=&cmsss=&cmss=2
(или я плохо смотрел ? )

Автор: marcusmae 24.1.2008, 21:01
Цитата(GrayCardinal @  24.1.2008,  20:04 Найти цитируемый пост)
или я плохо смотрел ?

Я бы сказал, что приведённая Вами ссылка - вообще единственное место, где упоминается aio безотносительно выбора системы на левом фрейме smile 

Ну, на SuSE, кстати, libaio ставится отдельно.

Автор: MAKCim 24.1.2008, 21:13
Добавлено @ 21:17
Цитата(marcusmae @  24.1.2008,  15:20 Найти цитируемый пост)
На этот счёт вопрос : достижимо ли хоть какое-то ускорение работы приложения при использовании асинхронного вывода вместо обычного?

да
пример
сервер + система логирования

Автор: marcusmae 24.1.2008, 21:36
MAKCim, у меня тоже есть повод для оптимизма : я получил ускорение для Windows - мне это удобнее всего smile Только толку от этого немного, поскольку, во-первых, там никакого POSIX AIO, а функции из kernel32, и во-вторых мне нужен вариант именно для Linux-систем.

Автор: MAKCim 24.1.2008, 21:57
marcusmae, 
вопрос то в чем?  smile 

Автор: marcusmae 24.1.2008, 22:34
MAKCim, вопрос в том, что асинхронный вывод под OpenSuSE работает медленнее обычного вывода с блокировкой.

Вот код с использованием aio_write :

Код

#define SIG_AIO SIGRTMIN+5

    // The async serialization boost wrapper.
    template<typename T> struct SerializeAsyncBinary {

        // The timeout between two sequential async operation status retrievings
        // in seconds.
        static const int GET_STATUS_TIMEOUT = 1; // seconds

        const GridVariable2d_Base<T>* var;
        const char* filename;

        aiocb* aioControlBlock;
        struct sigaction* action;

        SerializeAsyncBinary(const GridVariable2d_Base<T>* var,
            const char* filename) :

        var(var), filename(filename),
        aioControlBlock(new aiocb()), action(new struct sigaction())

        {
            // Fill the AIO control block structure with zeros.
            bzero(this->aioControlBlock, sizeof(aiocb)); 

            // Setup the signal handler.
            this->action->sa_sigaction = SerializeAsyncBinary::aioHandler;
            this->action->sa_flags = SA_SIGINFO;
            sigemptyset(&this->action->sa_mask);
            sigaction(SIG_AIO, this->action, NULL);

            this->aioControlBlock->aio_fildes = open(filename, O_CREAT | O_WRONLY); 
            this->aioControlBlock->aio_offset = 0; 
            this->aioControlBlock->aio_buf = (void*)var->dataInstance; 
            this->aioControlBlock->aio_nbytes = var->size; 
            this->aioControlBlock->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
            this->aioControlBlock->aio_sigevent.sigev_signo = SIG_AIO;
            this->aioControlBlock->aio_sigevent.sigev_value.sival_ptr = this;
            this->aioControlBlock->aio_reqprio = 1;
            
            if (aio_write(this->aioControlBlock))
                throw std::logic_error("Te file write operation failed.");            
        }

        static void aioHandler(int signal, siginfo_t* info, void* uap) {

            if (signal = SIG_AIO)
            {
                SerializeAsyncBinary<T>* async = (SerializeAsyncBinary<T>*)info->si_value.sival_ptr;
                if (aio_return(async->aioControlBlock) != async->var->size)
                    throw std::logic_error("The number of bytes written mismatch.");
                delete async;
            }
        }

        ~SerializeAsyncBinary() {

            close(this->aioControlBlock->aio_fildes);

            delete this->action;
            delete this->aioControlBlock;

            delete this->var;
            delete this->filename;
        }
    };


А вот обычный вывод :

Код

    // Serialize the specified 3d grid variable instance.
    static void Serialize(
        const GridVariable3d<T>* var3d, const char* filename) {
        std::ofstream file(filename, ios::out | ios::binary);

        if (var3d->composite)
        {
            // Write the header and data separately.
            file.write((char*)var3d->dataInstance, GridVariable3d::HEADERSIZE);
            file.write((char*)var3d->values,  var3d->nv * sizeof(T));
        }
        else
            // Write the header and data simultaneously.
            file.write((char*)var3d->dataInstance, var3d->size);

        file.close();
    }




Автор: MAKCim 24.1.2008, 22:42
marcusmae, 
естественно, асинхронный I/O не в любом случае дает преимущества
он оправдан, когда приходится читать или писать большие объемы данных, и этот процесс не должен снижать интерактивность
больший выигрыш можно получить на MP-системе

Автор: marcusmae 24.1.2008, 22:50
Цитата(MAKCim @  24.1.2008,  22:42 Найти цитируемый пост)
он оправдан, когда приходится читать или писать большие объемы данных


Сколько? У меня разом пишется 200мб на фоне ёмких вычислений. То есть, выводы не накладываются др на друга. Да и под виндовс ускоряется.

Цитата

больший выигрыш можно получить на MP-системе


на многоядерной то есть?

Автор: MAKCim 24.1.2008, 23:02
Цитата(marcusmae @  24.1.2008,  22:50 Найти цитируемый пост)
на многоядерной то есть?

на любой MP
в том числе многоядерной
Цитата(marcusmae @  24.1.2008,  22:50 Найти цитируемый пост)
Сколько? У меня разом пишется 200мб на фоне ёмких вычислений. То есть, выводы не накладываются др на друга. Да и под виндовс ускоряется.

ну 200МБ это достаточно много
а как ты скорость замерял?

Автор: marcusmae 24.1.2008, 23:16
Цитата(MAKCim @  24.1.2008,  23:02 Найти цитируемый пост)
а как ты скорость замерял?


На стороне теста (fortran) :

Код

call cpu_time(beginTime)
...
call cpu_time(endTime)


не самый лучший способ для экстремального тайминга : у этой функции не очень хорошее разрешение. Но значительные различия она улавливает.

А многоядерность - всё же странное решение проблемы. Освобождая от тормозов, связанных с выводом одно ядро, это счастье просто прибывает другому ядру.

Автор: marcusmae 25.1.2008, 01:21
GrayCardinal, я включил PCBSD. Вижу, поставить на него компиляторы Intel - целая проблема. Хотя, возможно, имея средство двоичной совместимости, можно попытаться запустить там уже готовые бинарники...

Автор: MAKCim 25.1.2008, 11:03
marcusmae, 
разница в том, что уведомление о завершении операции асинхронного I/O приходит после физической записи данных на устройство
если же использовать обычные операции write()/read() (без O_SYNC), то они возвращают управление после отправки пакета bio планировщику I/O, т. е до физической записи на устройство
поэтому время работы асинхронных функций при таком способе измерения времени больше
тем более у тебя в примере используется ofstream :: write(), который так же как и fwrite() буферизируем, т. е возврат управления может происходить еще раньше (нет обращения к ядру, а данные записываются в user-level буфер)

Цитата(marcusmae @  24.1.2008,  23:16 Найти цитируемый пост)
А многоядерность - всё же странное решение проблемы

я такого не говорил
читай внимательнее
MP - это способ повысить общее быстродействие приложения, использующее операции асинхронного I/O

Автор: marcusmae 25.1.2008, 12:26
Цитата(MAKCim @  25.1.2008,  11:03 Найти цитируемый пост)
 уведомление о завершении операции асинхронного I/O приходит после физической записи данных на устройство

Да, более того, можно вообще обойтись без уведомления, если не заказывать получение сигнала.

Цитата(MAKCim @  25.1.2008,  11:03 Найти цитируемый пост)
если же использовать обычные операции write()/read() (без O_SYNC), то они возвращают управление после отправки пакета bio планировщику I/O, т. е до физической записи на устройство

Я конечно не знаток никсов, но что-то мне это кажется малоправдоподобным. А что, если, допустим, понадобится записать и тут же этот файл считать? Read ведь не выдаст отказ в доступе? Где-то можно прочитать об этом?

Цитата(MAKCim @  25.1.2008,  11:03 Найти цитируемый пост)
поэтому время работы асинхронных функций при таком способе измерения времени больше

Нет, нелогично smile Я замеряю время работы итераций цикла, отягощённых тем или иным способом вывода. Скорость асинхронного вывода оттуда нельзя измерить : если зажать его в cpu_time, то разность просто равна нулю. Ну а длительность обычных write-ов, кстати, вполне осязаема.

Я вот что думаю : может, какая-то тонкая настройка системы играет роль?
Цитата

I/O-bound versus CPU-bound processes
A process that is I/O bound is one that performs more I/O than processing. A CPU-bound process does more processing than I/O. The Linux 2.6 scheduler actually favors I/O-bound processes because they commonly initiate an I/O and then block, which means other work can be efficiently interlaced between them.

Автор: MAKCim 25.1.2008, 12:49
Цитата(marcusmae @  25.1.2008,  12:26 Найти цитируемый пост)
Я конечно не знаток никсов, но что-то мне это кажется малоправдоподобным. А что, если, допустим, понадобится записать и тут же этот файл считать? Read ведь не выдаст отказ в доступе? Где-то можно прочитать об этом?

для каждого файла в Linux существует кэш страниц, в которых кэшируются операции I/O
при записи в файл модифицируется соответствующая страница (или страницы) его кэша
далее, запрос на чтение будет удовлетворен из него (т. е из памяти)
потоки ядра pdflush выполняют запись модифицированных страниц на диск
Цитата(marcusmae @  25.1.2008,  12:26 Найти цитируемый пост)
Нет, нелогично

т. е ты при использовании асинхронного I/O конечное время высчитываешь не после получения уведомления о завершении операции I/O

Автор: marcusmae 25.1.2008, 13:05
Цитата(MAKCim @  25.1.2008,  12:49 Найти цитируемый пост)
потоки ядра pdflush выполняют запись модифицированных страниц на диск


MAKCim, спасибо за информацию! = К своему стыду я не слишком засиживаюсь за чтением книжек по внутреннему устройству Unix. Скажите, а есть ли способы настройки того процесса, что Вы описали?

Цитата(MAKCim @  25.1.2008,  12:49 Найти цитируемый пост)
т. е ты при использовании асинхронного I/O конечное время высчитываешь не после получения уведомления о завершении операции I/O

Да. Меня в большей степени волнует, с какой скоростью будет работать программа. Впрочем, Вы правы, стоило бы засечь время от aio_write до SIG_AIO.

Автор: MAKCim 25.1.2008, 13:13
Цитата(marcusmae @  25.1.2008,  13:05 Найти цитируемый пост)
Да. Меня в большей степени волнует, с какой скоростью будет работать программа

вот
естественно, инициализация aiocb и выполнение вызова aio_write() может занимать больше времени, нежели ofstream :: write()
однако это вовсе не означает, что физическая запись на диск во втором случае будет осуществлена быстрее
Цитата(marcusmae @  25.1.2008,  13:05 Найти цитируемый пост)
Скажите, а есть ли способы настройки того процесса, что Вы описали?

какого плана настройки?

Автор: marcusmae 25.1.2008, 15:14
Цитата(MAKCim @  25.1.2008,  13:13 Найти цитируемый пост)
какого плана настройки?

Ну вот CPU-bound и I/O-bound процессы? = О чём может идти речь?

Автор: MAKCim 25.1.2008, 17:19
Цитата(marcusmae @  25.1.2008,  15:14 Найти цитируемый пост)
Ну вот CPU-bound и I/O-bound процессы? = О чём может идти речь?

это совсем из другой темы
а именно, для более гибкой реализации стратегии планирования процессов

Автор: marcusmae 31.1.2008, 13:44
MAKCim, напрасно я переживал : на реальном SuSE (без виртуальной машины) всё оказалось лучше, чем я думал (графики присоединены). Остаётся маленькая проблемка, связанная с тем, что генерируемые в асинхронном варианте файлы получают ограниченные права на доступ. Наверно дело в этой строчке

Код

this->aioControlBlock->aio_fildes = open(filename, O_CREAT | O_WRONLY); 


http://ipicture.ru/Gallery/Viewfull/439764.html

Маленькая поправка : Xeon всё-таки по-быстрее : 2,6 GHz.

Теперь пробовать на реальных задачах  smile



Автор: MAKCim 31.1.2008, 17:13
Цитата(marcusmae @  31.1.2008,  13:44 Найти цитируемый пост)
Наверно дело в этой строчке

угу
нужно так
Код

this->aioControlBlock->aio_fildes = open(filename, O_CREAT | O_WRONLY, 0666);

0666 - битовая маска прав в 8-ой СС
подробнее man 2 chmod

Добавлено через 2 минуты и 21 секунду
Цитата(marcusmae @  31.1.2008,  13:44 Найти цитируемый пост)
на реальном SuSE (без виртуальной машины) всё оказалось лучше, чем я думал

что же ты раньше не сказал, что на виртуальной машине тестировал?  smile 

Автор: marcusmae 31.1.2008, 19:00
Цитата(MAKCim @  31.1.2008,  17:13 Найти цитируемый пост)
нужно так

спасибо!

Цитата(MAKCim @  31.1.2008,  17:13 Найти цитируемый пост)
что же ты раньше не сказал, что на виртуальной машине тестировал?   

Нда, sorry, явно не сказал. Я расчитывал, она хоть динамику будет воспроизводить. Не тут-то было smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)