Я работаю над версией ядра Linux 2.6.35.9 и пытаюсь отключить объединение команд.
Вывод lspci
показан ниже:
00:00.0 Host bridge: Intel Corporation 82P965/G965 Memory Controller Hub (rev 02)
00:01.0 PCI bridge: Intel Corporation 82P965/G965 PCI Express Root Port (rev 02)
00:19.0 Ethernet controller: Intel Corporation 82566DC Gigabit Network Connection (rev 02)
00:1a.0 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #4 (rev 02)
00:1a.1 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #5 (rev 02)
00:1a.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #2 (rev 02)
00:1c.0 PCI bridge: Intel Corporation 82801H (ICH8 Family) PCI Express Port 1 (rev 02)
00:1c.4 PCI bridge: Intel Corporation 82801H (ICH8 Family) PCI Express Port 5 (rev 02)
00:1d.0 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #1 (rev 02)
00:1d.1 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #2 (rev 02)
00:1d.2 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #3 (rev 02)
00:1d.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #1 (rev 02)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev f2)
00:1f.0 ISA bridge: Intel Corporation 82801HH (ICH8DH) LPC Interface Controller (rev 02)
00:1f.2 RAID bus controller: Intel Corporation 82801 SATA RAID Controller (rev 02)
00:1f.3 SMBus: Intel Corporation 82801H (ICH8 Family) SMBus Controller (rev 02)
01:00.0 VGA compatible controller: nVidia Corporation G72 [GeForce 7300 LE] (rev a1)
04:03.0 Mass storage controller: Promise Technology, Inc. PDC20268 (Ultra100 TX2) (rev 02)
На моих дисках включена собственная очередь команд.
Я смотрел на спецификацию Serial ATA AHCI 1.3 и обнаружил на странице 115, что -
Функция CCC используется только тогда, когда CCC_CTL.EN установлен в «1».Если CCC_CTL.EN установлен в '0', прерывания CCC не должны генерироваться.
Далее я взглянул на соответствующий код (а именно, файлы, касающиеся AHCI) для этой версии ядра, но не смог добиться какого-либо прогресса.Я нашел следующее macro enum HOST_CAP_CCC = (1 << 7)
в drivers/ata/ahci.h
, но я не уверен, как это следует изменить, чтобы отключить объединение команд.
Может кто-нибудь помочь мне определить, какCCC можно отключить?Спасибо!
В ответ на комментарий gby:
Я провел эксперимент, в котором выдавал запросы размером 64 КБ из кода моего драйвера.64 КБ соответствуют 128 секторам (каждый сектор = 512 байт).
Когда я смотрю на различия в метках времени ответа, вот что я нахожу:
Timestamp | Timestamp | Difference
at | at | in microsecs
Sector 255 - Sector 127 = 510
Sector 383 - Sector 255 = 3068
Sector 511 - Sector 383 = 22
Sector 639 - Sector 511 = 22
Sector 767 - Sector 639 = 12
Sector 895 - Sector 767 = 19
Sector 1023 - Sector 895 = 13
Sector 1151 - Sector 1023 = 402
Как видите, отметка времени отклика различия, по-видимому, указывают на то, что прерывания завершения записи объединяются в один, а затем создается одно единственное прерывание, что может объяснить действительно низкие значения в десятках микросекунд.
Кроме того,при проведении этого эксперимента кэш записи на диск был отключен с помощью hdparm
.
. Очевидно, что здесь используется некоторая пакетная обработка прерываний, которую мне нужно отключить, чтобы прерывание вызывалось для каждый икаждый запрос на запись.
ОБНОВЛЕНИЕ: Вот еще один эксперимент, который я попробовал.
Создайте структуру bio
в моем драйвере и вызовите__make_request()
функция драйвера нижнего уровня.Только один 2560-байтовый запрос на запись отправляется моим драйвером.
После обслуживания этой записи генерируется прерывание, которое перехватывается do_IRQ()
.Наконец, вызывается функция blk_complete_request()
.Имейте в виду, что мы все еще находимся в верхней половине обработчика прерываний (т. Е. Контекст прерывания, не контекст ядра).Теперь мы сочиняем еще один struct bio
в blk_complete_request()
и вызываем функцию __make_request()
драйвера более низкого уровня.Мы записываем отметку времени в этот момент (скажем, T_0
).Когда обратный вызов завершения запроса получен, мы записываем другую временную метку (назовите ее T_1
).Разница - T_1 - T_0
- всегда выше 1 миллисекунды.Этот эксперимент повторялся много раз, и каждый раз сектор назначения влиял на эту разницу - T_1 - T_0
.Было отмечено, что если сектора назначения разделены приблизительно 350 секторами, разница во времени составляет около 1,2 миллисекунда для запросов размером 2560 байт.
Каждый раз следующий запрос на запись отправляется только тогда, когда предыдущий запрос имеетбыл обслужен.Итак, все эти запросы связаны , и диск должен обслуживать только один запрос за один раз.
Насколько я понимаю, поскольку целевые сектора последовательных запросов были разделены довольно большимколичество, к моменту следующего запроса, запрашиваемый сектор будет почти ниже головки диска и, следовательно, запись должна произойти немедленно и T_1 - T_0
должно быть мало (по крайней мере <1 миллисекунда). </p>
Спецификация Serial ATA AHCI 1.3 (стр. 114) гласит, что:
Когда заданное число команд в программном обеспечении завершено или истекло указанное время ожидания программного обеспечения , аппаратное прерывание генерируетсячтобы позволить программному обеспечению обрабатывать завершенные команды.
Я предполагаю, что этот таймер может быть причиной того, что задержка каждого запроса превышает 1 миллисекунд.Вот почему мне нужно отключить CCC.
Iсделал письмо автору - Джеффу Гарзику - но я еще не получил известие от него. Он зарегистрированный пользователь на stackoverflow? Если да, я могу отправить его в личку ...
Используемый нами жесткий диск: WD Caviar Black (номер модели - WD1001FALS).
Кто-нибудь? : - (