Внутреннее устройство Vista SP1 – улучшения в части копирования файлов

В пакете обновления 1 (SP1) для ОС Windows Vista, если сравнивать его с первоначальным выпуском Vista, наблюдается ряд изменений в сферах совместимости приложений, поддержки устройств, управления питанием, безопасности и надежности. Подробный список таких изменений изложен в документе «Заметные изменения в пакете обновления 1 (SP1) для ОС Windows Vista» (на английском языке), который можно загрузить здесь. В частности, упомянутый документ повествует об увеличившейся производительности копирования файлов в некоторых сценариях, как то создание локальных копий в пределах одного диска, копирование файлов с удаленных машин, работающих под управлением других ОС, и копирование файлов между системами, оснащенными ОС Windows Vista с пакетом обновления 1 (SP1). За счет чего же удалось достичь таких результатов? Ответ на этот вопрос весьма нетривиален. Все дело в изменениях механизма копирования файлов в Windows Vista по сравнению с Windows XP, с одной стороны, и в дальнейших усовершенствованиях, внесенных в Windows Vista пакетом обновления 1 (SP1), с другой. Поскольку копировать файлы приходится всем, мне подумалось, что будет нелишне, отвлекшись на время от разбора «дел», проследить развитие механизма копирования файлов и понять, каким же образом возросла его производительность в пакете обновления 1 (SP1).

Казалось бы, копирование файла – чрезвычайно простая операция. Достаточно открыть исходный файл, создать конечный файл, после чего считать первый и произвести запись во второй. На практике же производительность копирования файлов измеряется по показателям точности индикации состояния, пропускной способности, потребления ресурсов процессора и памяти. Как правило, оптимизация по одному из этих показателей приводит к ухудшению остальных. Хуже того – некоторые семантические данные, которые могли бы помочь механизму копирования данных находить оптимальные решения, для него недоступны. К примеру, если было бы известно, что пользователь не планирует обращаться к конечному файлу, который создается при копировании, можно было бы отказаться от кэширования данных этого файла. С другой стороны, если бы конечный файл был предназначен для немедленного доступа из другого приложения или, как в случае с файловым сервером, для общего доступа клиентскими системами, то можно было бы прибегнуть к интенсивному кэшированию в системе назначения.

Механизм копирования файлов в предыдущих версиях Windows
Механизм копирования файлов Windows нацелен на успешную работу в любых сценариях – настолько, насколько это вообще возможно, учитывая неизбежность компромиссных решений и нехватку значимой информации. До появления ОС Windows Vista механизм был тривиален. Исходный и конечный файлы открывались в режиме кэширования, затем исходный файл последовательно считывался фрагментами по 64 КБ (при создании сетевых копий вследствие ограничений по размеру блоков чтения, налагаемых протоколом SMB1.0, размер фрагмента уменьшался до 60 КБ), и эти фрагменты передавались в конечный файл. При доступе к файлу путем ввода-вывода с кэшированием (в отличие от ввода-вывода в режиме отображения в памяти и ввода-вывода без буферизации) данные, подлежащие чтению и записи, сохраняются в памяти как минимум до того момента, когда диспетчер памяти решит, что эта память нужна для других целей (в частности, для кэширования данных других файлов).
Асинхронное упреждающее чтение в ходе копирования производилось диспетчером кэша Windows. Пока исходный файл считывался в фоновом режиме, проводник записывал данные на другом диске или в удаленной системе. Посредством механизма записи с задержкой, реализованной диспетчером кэша, содержимое скопированного файла своевременно перемещалось из памяти на диск. Таким образом, при необходимости ресурсы памяти можно было направить на решение других задач, а в случае неисправности диска или сбоя системы ущерб от потери данных должен был быть минимальным. Действие описанного алгоритма наглядно демонстрирует следующая трассировка, сделанная программой Process Monitor. Она показывает, как файл размером 256 КБ в среде Windows XP копируется из одного каталога в другой, а для выделения операций чтения и записи включены соответствующие фильтры.

clip_image002

Первому событию соответствует предпринятая проводником попытка считывания данных, отсутствующих в памяти. В связи с этим диспетчер кэша осуществляет ввод-вывод без кэширования (чтение или запись данных напрямую с диска или на диск без кэширования в памяти). Выборка данных с диска соответствует событию 1 (см. трассировку стека ниже).

clip_image002[4]

Согласно трассировке стека, вызов ReadFile проводником осуществляется в строке 22 посредством функции BaseCopyStream, а диспетчер кэша опосредованно вызывает операцию чтения без кэширования, воздействуя на отображение файла в памяти и вызывает ошибку страницы в строке 8.

Так как проводник открывает файл с рекомендацией о последовательном доступе (не отраженной в трассировке), то поток чтения с опережением диспетчера кэша, исполняемый в рамках процесса System, начинает агрессивное чтение файла от имени проводника (см. события 2 и 3). Функции чтения с опережением показаны в событии 2 трассировки стека.

clip_image002[6]

Вероятно, вы заметили, что операции чтения с опережением первоначально осуществляются вне последовательности, которая была задана исходным чтением без кэширования, инициированным первой операцией чтения проводника. Такая ситуация может привести к дополнительному позиционированию головки диска и снижению производительности. Впрочем, когда проводник обнаруживает данные, ранее считанные диспетчером кэша, а его запросы на чтение начинают обслуживаться из памяти, он прекращает инициировать операции ввода-вывода без кэширования. Как правило, в ходе копирования файлов диспетчер кэша опережает проводник на 128 КБ.

Событие 4 трассировки стека содержит первый запрос на чтение проводника. За ним следует серия чередующихся запросов на запись и чтение. В конце трассировки поток записи с задержкой диспетчера кэша, также исполняемый в рамках процесса System, сбрасывает данные конечного файла на диск путем записи без кэширования.

Какие изменения механизм копирования файлов претерпел с выходом Windows Vista
В процессе работы над ОС Windows Vista группа разработки продукта внесла в механизм копирования файлов изменения, призванные оптимизировать его работу в ряде важнейших сценариев. Один из самых значительных огрехов в реализации этого механизма заключается в том, что при копировании данных большого объема поток записи с задержкой диспетчера кэша в конечной системе зачастую не поспевает за записью данных и их кэшированием в памяти. При этом данные переполняют память, заставляя удалять из неё другие полезные данные и код. В конечном счете память становится туннелем, через который данные передаются со скоростью, заданной возможностями диска. 

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

С такими сравнительно компактными и чередующимися операциями с файлами связана определенная проблема. Дело в том, что драйвер файловой системы SMB, реализующий протокол удаленного общего доступа к файлам Windows, не поддерживает конвейерную обработку данных в сетях с высокой пропускной способностью и значительной задержкой передачи данных (WLAN). Каждый раз, когда локальная система ожидает получения данных удаленной системой, передача данных замедляется, и копирование неизбежно сопровождается задержкой, связанной с обменом подтверждениями и ожиданием последующих блоков данных.

Изучив различные альтернативы, для решения выявленных проблем разработчики решили реализовать механизм копирования, ориентированный на большие асинхронные операции ввода-вывода без кэширования. При вводе-выводе без кэширования данные копируемых файлов не занимают место в памяти локальной системы, а значит, её содержимое сохраняется. Асинхронные операции ввода-вывода крупных файлов позволяют организовать конвейерную обработку данных в сетях со значительной задержкой. Нагрузка на процессор сокращается в связи с тем, что диспетчеру кэша не приходится заниматься распределением памяти. Решение перейти на ввод-вывод без кэширования было принято отчасти из-за неэффективной обработки первоначальной версией диспетчера кэша ОС Windows Vista операций ввода-вывода крупных файлов. Размер операций ввода-вывода все же ограничен. Это связано с тем, что перед записью данных механизму копирования необходимо выполнить их чтение, причем эти две операции желательно производить одновременно, что особенно актуально при копировании между разными дисками или системами. Крупные операции ввода-вывода сложны с точки зрения корректной оценки их продолжительности, поскольку точек измерения хода операции и обновления оценки меньше, чем в других случаях. Не остался незамеченным разработчиками и существенный недостаток ввода-вывода без кэширования – при копировании большого количества небольших файлов головка диска постоянно перемещается от исходного файла к конечному, затем обратно к исходному и т.д.
По результатам длительного анализа, сравнения эффективности и корректировки разработчики реализовали алгоритм, предусматривающий для файлов размером менее 256 КБ ввод-вывод с кэшированием. При работе с файлами размером свыше 256 КБ механизм обращается к внутренней таблице и с её помощью определяет количество и размер блоков ввода-вывода без кэширования, которые он сможет единовременно обработать. Число таких блоков варьируется от 2 при копировании файлов размером менее 2 МБ до 8 при копировании файлов крупнее 8 МБ. Размер блока ввода-вывода равен размеру файла, если файл меньше 1 МБ. Для файлов размером до 2 МБ он составляет 1 МБ, а для более крупных файлов – 2 МБ.

К примеру, чтобы скопировать файл размером 16 МБ, механизм копирования инициирует восемь асинхронных операций чтения исходного файла без кэширования по 2 МБ на каждую, дожидается их завершения, затем инициирует восемь асинхронных операций записи в конечный файл (опять же без кэширования), дожидается их завершения, после чего повторяет цикл. Эта модель хорошо просматривается в выполненной программой Process Monitor трассировке копирования файла размером 16 МБ с локальной на удаленную систему.

clip_image002[8]

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

clip_image002[10]

Обратите внимание, что смещение операции записи меняется сразу с 327 680 на 458 752, а блок со смещением 393 216 оказывается пропущен. Этот пропуск вызывает повторное позиционирование головки диска, а файловая система NTFS инициирует дополнительную операцию записи в пропущенной области для обнуления части файла. Именно поэтому на смещение 393 216 приходятся две операции записи. В трассировке стека, соответствующей выделенному событию, видно, как NTFS вызывает функцию CcZeroData диспетчера кэша, чтобы обнулить пропущенный блок.

clip_image002[12]

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

Вероятно, самый значительный недостаток рассматриваемого алгоритма, на который жаловались многие пользователи ОС Windows Vista, заключается в том, что при копировании большого набора файлов размером от 256 КБ до нескольких десятков мегабайт воспринимаемая производительность иногда оказывается существенно ниже, чем в ОС Windows XP. Дело в том, что файловый ввод-вывод с кэшированием, реализованный в старом алгоритме, позволял проводнику записывать конечные файлы в память и закрывать диалоговое окно копирования задолго до того, как поток записи с задержкой диспетчера кэша фактически сохранял данные на диске. Теперь, когда в ОС Windows Vista реализован алгоритм без кэширования, проводник вынужден перед инициированием каждой последующей операции дожидаться завершения операции текущей, а для того, чтобы сообщить о завершении операции копирования файлов, необходимо, чтобы все скопированные данные фактически оказались на диске. Кроме того, проводник в Windows Vista ждет 12 секунд перед оценкой продолжительности операции копирования. При этом сам алгоритм оценки чувствителен к колебаниям скорости копирования. Сочетание этих двух факторов усиливает недовольство пользователей медленным копированием.

Улучшения в пакете обновления 1 (SP1)
В ходе разработки пакета обновления 1 (SP1) для ОС Windows Vista участники группы разработки решили пересмотреть механизм копирования, чтобы найти способы улучшения фактической и воспринимаемой производительности операций копирования в ситуациях, с которыми новая реализация справлялась неудовлетворительно. Наиболее значимым стало их решение возвратиться к файловому вводу-выводу с кэшированием при копировании всех локальных и удаленных файлов за одним лишь исключением, о котором я вскоре расскажу. Кэширование позволило сократить воспринимаемое время копирования и повысить производительность в сценариях публикации. Для того, чтобы преодолеть вышеописанные недостатки ввода-вывода с кэшированием, потребовалось внести существенные изменения как в алгоритм копирования файлов, так и в платформу.

Тот самый исключительный случай, когда механизм копирования файлов ОС Windows Vista с пакетом обновления 1 (SP1) не прибегает к кэшированию, связан с копированием удаленных файлов. Проблема двукратного кэширования в этом случае решается при помощи клиентского драйвера удаленной файловой системы Windows –Rdbss.sys. Этому драйверу отправляется команда, препятствующая кэшированию удаленного файла в локальной системе в ходе его чтения или записи. Запуск этой команды проводником виден в следующем фрагменте журнала программы Process Monitor.

clip_image002[14]

Еще одно улучшение в части копирования файлов на удаленную систему связано с конвейерным вводом-выводом, который инициируется драйвером файловой системы SMB2 – srv2.sys, впервые появившемся в ОС Windows Vista и Windows Server 2008. Если в первоначальной реализации протокола SMB по сети передавались блоки ввода-вывода размером 60 КБ, то в версии SMB2 им на смену пришли блоки размером 64 КБ с поддержкой конвейеризации. В результате, принимая от приложения крупный блок ввода-вывода, протокол может одновременно инициировать множество блоков по 64 КБ, а значит, передача данных в удаленную систему и из неё происходит с меньшей задержкой.

Кроме того, механизм копирования инициирует четыре начальных блока ввода-вывода в размере от 128 КБ до 1 МБ (в зависимости от размера копируемого файла). После этого поток чтения с опережением диспетчера кэша начинает инициировать крупные операции ввода-вывода. Изменения, внесенные в платформу в ходе разработки пакета обновления 1 (SP1), касаются диспетчера кэша и позволяют ему обрабатывать более крупные операции ввода-вывода с помощью чтения с опережением и записи с задержкой. Укрупнение блоков ввода-вывода стало возможным лишь благодаря работе, проведенной при разработке первоначальной версии системы ввода-вывода ОС Windows Vista. Эта работа была направлена на поддержку блоков размером свыше 64 КБ и тем самым на снятие ограничения, характерного для предыдущих версий ОС Windows. Ввод-вывод большими блоками повышает производительность и при локальном копировании, так как сокращается частота обращений к диску и операций позиционирования головки. Кроме того, он помогает потоку записи с задержкой диспетчера кэша поспевать за скоростью заполнения памяти скопированными данными файлов. Это уменьшает, хотя и не исключает вероятность критической нехватки памяти, при которой активное содержимое памяти в ходе копирования уничтожается. Наконец, при удаленном копировании крупные блоки ввода-вывода позволяют драйверу SMB2 задействовать конвейерную обработку. Диспетчер кэша может инициировать блоки ввода-вывода на чтение, которые по размеру в два раза больше блоков, генерируемых приложениями – до 2 МБ в Windows Vista и до 16 МБ в Windows Server 2008. Блоки ввода-вывода на запись в Windows Vista могут достигать 1 МБ, а в Windows Server 2008 – 32 МБ.

Нижеследующая трассировка демонстрирует фрагмент операции копирования файла размером 16 МБ с одной системы под управлением Windows Vista SP1 в другую. Проводник инициирует блоки ввода-вывода размером 1 МБ, а поток чтения с опережением диспетчера кэша (он обозначен флагом ввода-вывода без кэширования) обрабатывает блоки размером 2 МБ.

clip_image002[16]

Изменения, реализованные в пакете обновления 1 (SP1) для ОС Windows Vista, хоть и обеспечивают в целом более высокую производительность, чем предыдущие версии Windows, но в некоторых специфических случаях производительность может быть ниже, чем в первоначальной версии Windows Vista. Первый такой случай – копирование в удаленную систему с ОС Windows Server 2003 или копирование из такой системы по медленному сетевому соединению. Механизм копирования в первоначальной версии Windows Vista справился бы с задачей быстро, но в связи с вышеупомянутой проблемой нарушения очередности операций ввода-вывода поведение диспетчера кэша системы с ОС Windows Server 2003 привело бы к заполнению памяти сервера данными копируемого файла. Изменения, внесенные в механизм копирования при разработке пакета обновления 1 (SP1), помогают решить эту проблему, однако в силу того, что размер блоков ввода-вывода сократился с 60 КБ до 32 КБ, пропускная способность в условиях соединения со значительной задержкой оказывается примерно в два раза ниже аналогичного показателя в первоначальной версии Windows Vista.

Другой сценарий, при котором механизм копирования в реализации пакета обновления 1 (SP1) уступает по производительности первоначальной версии Windows Vista, связан с копированием больших объемов данных в рамках одного раздела. Так как в пакете обновления 1 (SP1) блоки ввода-вывода меньше (в основном, это сделано для того, чтобы предоставить другим компонентам системы беспрепятственный доступ к диску, а значит, повысить реактивность во время копирования), головка диска в период между чтением из исходных файлов и записью в файлы конечные позиционируется чаще. Это особенно ощутимо при работе с дисками, которые не оснащены внутренними алгоритмами организации очередей, позволяющими оптимизировать позиционирование.

Стоит заметить, что с появлением пакета обновления 1 (SP1) проводник стал рассчитывать время копирования гораздо быстрее, чем в первоначальном выпуске Windows Vista, а алгоритм расчета стал более точным.

Резюме
Копирование файлов – не настолько простая операция, как это может показаться на первый взгляд. Группа разработки ОС Windows Vista очень серьезно отнеслась к отзывам пользователей и провела не одну сотню часов, пробуя различные подходы и корректируя конечную реализацию для решения поставленной задачи – восстановить производительность большинства сценариев копирования как минимум на уровне предыдущих версий Windows и радикально повысить производительность в ряде важнейших сценариев. Изменения равным образом действительны при копировании как через проводник, так и посредством сторонних приложений, работающих с API CopyFileEx. Наиболее серьезных улучшений по сравнению с предыдущими версиями ОС Windows удалось достичь при копировании файлов в сетях со значительной задержкой и высокой пропускной способностью. В таких условиях благодаря крупным блокам ввода-вывода, конвейерной обработке ввода-вывода протоколом SMB2 и автонастройке окна получения стека TCP/IP те задачи, которые в ОС Windows XP или Windows Server 2003 заняли бы десять минут, теперь решаются в течение минуты. Недурственно.

Оригинал записи