Редактирование истории в гите довольно запутано. Пользоваться git rebase/git cherry-pick может быть довольно тяжело.
Хм, по-моему, оно становится тривиально понятным, если разобраться, что же вообще происходит с историей и почему она редактируется именно в виде последовательности патчей. Дальше начинает влиять собственно объективная сложность процесса - которая тут может быть достаточно заметна и от которой хотят уйти те, кто просто хотят думать по принципу "вот это состояние работает, а дальше мне лень".
Или условно: разделить коммит в середине длинной ветки на два.
То же самое. Да, тут надо наперёд сообразить, где делить, и какой командой затем получить изменения для деления. `git status` помогает найти следующий коммит, в стиле:
Next commands to do (6 remaining commands):
pick f253d4cd Track file times in both subspools
а git restore - применить его изменения без коммита. А затем разобраться, какую именно часть действий вложить в индекс - вот тут можно запутаться, если оно слишком перемешано. Увы.
Работа со stash и другими грязными изменениями. В гите требуется вручную разобраться со всеми незакоммиченными изменениями, прежде чем выйдет переключиться на другую ветку (например, быстро глянуть, а что там на мастере)
Это "вручную разобраться" это одна команда stash (можно добавить -a, чтобы вообще всё вкинуло в сохранение). Ну или коммит всего. И то требуется, если надо получить дерево состояния того же мастера, а не просто список коммитов - для последнего и переключаться не надо. Объективно, два разных файловых дерева не могут лежать в одном каталоге, или вы не согласны? Кстати, не помню названия, но для быстрого переключения всем деревом был плагин с компактными командами.
Многие не понимают (на уровне интуиции), зачем нужен git gc.
Ну так для них есть автомат, который запускает gc через какой-то объём действий.
Чаще всего, люди плохо себе представляют, что происходит с графом коммитов, когда мы, например, удаляем один коммит из середины истории.
Хм, я не очень любитель читать документацию, но, по-моему, там совершенно тривиально. Что именно в этом можно не понять?
Две проблемы обозначенные вначале - объективны.
Если и так, то они минимально связаны конкретно с Git.
Mercurial успешнее, чем Git, изображает то, что реально нужно ≈90 процентам пользователей - использовать распределённую VCS как централизованную, при этом получая некоторые фишки распределённости в виде временного (долго всё равно не нужно) сохранения коммита (changeset, в терминах Mercurial) у локального пользователя. Полные фишки Git всё равно мало кто использует, слово index уже пугает значительную часть пользователей, а rebase вообще аватарой аццкого сотоны в пределах рабочей копии. В эту сторону работают такие фишки, как последовательная нумерация ченжсетов, вписывание имени текущей ветки в метаданные коммита, и тот же отказ от индекса, который требует других, сильно более топорных инструментов, но при этом визуально более наглядных.
В чём-то я их понимаю - я тоже раз пять делал - "git diff" - "что??? где мои правки???" - "git status" - "ааа блин, они в индексе, смотрим git dc (алиас у меня такой)", и пока не научился делать какой-нибудь "git rebase --abort" и вообще внимательно читать вывод git status, пару раз таки делал как на xkcd нарисовано - убить рабочую копию, стянуть с нуля и сделать заново. Сейчас уже не делаю, но это потому, что я понимал, что если ничего не получается, надо прочесть внимательно ;)
Бранчи там организованы сложно. Если сравнивать с hg.
Бранчи в Hg организованы сложно. Если сравнивать с Git.
Сами авторы Hg пишут в документации, что «The term branch is sometimes used for slightly different concepts. This may be confusing for new users of Mercurial.» - прямая цитата из родной вики. В Hg понятие ветки это смешение нескольких разнородных сущностей в одну не сильно приятную (именно из-за смешения) кашу:
1. «Голова» процесса развития, которых может быть несколько в пределах одной рабочей копии или «ветки» в другом понимании. При операциях push, pull передаются все эти головы. В некоторых местах это называется напрямую словом head.
2. Некий установленный локальным режимом тег под названием «branch», который приклеивается к каждому новому changesetʼу, и больше ничего не делает. Именно его чаще всего называют «веткой».
3. Полный пучок п.1, между которыми тоже можно переключаться (множественные головы, которые используются ничтожной частью пользователей, но которые всем надо учитывать).
4. Bookmarks, которые тоже ветки, аналогично Git, но не получили такое имя из-за намеренного отказа разработчиков.
После этого в Git всё тривиально. А основную обиду большинства сторонников Mercurial получает то, что нет автомата, который пишет название локальной ветки-2 при коммите в атрибуты коммита. В Git это решается явной записью в сообщение коммита, причём чаще всего не в виде ветки, а в виде тикета, под который идёт разработка.
А при чём тут вообще быть системным программистом к пониманию того, что любое изменение что-то делает в составе файлов и/или в их содержании? Это уровень простого юзера ПК, даже не программиста.
Кажется, слишком много коней и людей смешались в одной куче.
Основное отличие jj от Git состоит в том, что история коммитов представляет из себя последовательность патчей, а не snapshot-ов.
В Git получить патч между коммитами-снапшотами не просто, а очень просто. Но любой патч будет содержать контекстно-зависимые данные - например, номера строк. Пусть в ветке v12 перед местом патча добавили 30 строк. Патч для v12 будет начинаться со строки 199, а для v11 начинался со 169. Это один и тот же патч, или разные? А если со 169 другое место для применения с тем же контекстом (патч ложится ровно)?
Идея взята из Darcs. Такой подход позволяет легко переписывать историю коммитов,
Не влияет.
rebase становится тривиальным,
Не становится. Те же проблемы наложения при изменении контекста.
коммиты (патчи) можно спокойно перемещать между ветками,
Не влияет.
конфликтов меньше (автоматическое разрешение конфликтов работает лучше, чем в Git или Mercurial).
Если стало работать лучше, то изменено что-то в этом самом методе автоматического разрешения конфликтов, а не в базе самого движка.
То, что вам показывают в формате git log -p или аналога дифф в случае одного родителя - оптимизация усилий на типовой случай. Уже при merge это не показывается, надо явно запрашивать.
Хохму с дракой за спинлоки я помню ещё в районе 2000 года. Сервер БД для хостинга поставили на MySQL на Linux, и увидели, что если в локи входят несколько одновременно клиентов, то их процессы начинают только и делать, что крутиться в ожидании освобождения, и в результате зависимость квадратичная от количества вошедших. Лечить это в коде мы тогда не могли, и мистическим образом улучшение настало от перевода на FreeBSD, где треды были сделаны на libc_r, старой и кривоватой, которая реально один системный процесс с переключением в юзерленде - и это работало лучше! Исправление наступило года через два с новыми версиями всего.
Реально такие нелинейные росты это основная проблема любой загрузки чего-то.
Ну, потому и неразумно хвалить/осуждать некую архитектуру за (не)соответствие тем или иным задачам. Можно, разве что, поругать пиарщиков IBM за их "360 градусов", что ни разу не правда даже на момент появления этой архитектуры -- но верить пиарщикам...
Ну почему же. Они говорили, что машина годится одновременно для математических, экономических и управляющих задач - чем не 360 градусов? ;) Ну при этом ещё и домен realtime они, скорее всего, просто не предполагали.
Ну дык не сделали ж соответствие -- причём уже имея возможность ознакомиться с чужим опытом (80386 -- это ближе к середине 1980-х, а VM/370 -- 1971-й, если память не изменяет). Вообще, в Интеле всю жизнь архитекторы были... странные.
Тут согласен на 300%, количество и специфику странных решений у них можно обсуждать часами.
Однако в любом случае факт остаётся фактом: на Системе 370 можно было реализовать ВМ, не имея никаких технических средств поддержки виртуализации, кроме собственно обычного механизма виртуальной памяти и обычного же разделения режимов выполнения на пользователь/супервизор, а в IA-32 это было невозможно.
У x86 этому не хватало буквально ограничения нескольких команд (SMSW, SIDT, STR, ещё какой-то, точно не помню). Вполне можно было поставить на них дополнительное ограничение, и получилось бы примерно так же.
Но тут вступает в силу следующий фактор. Виртуализация классического стиля Попек-Голдберг предполагает, что хозяйская система ведёт теневые страницы механизма DAT, иначе не может справиться с трансляцией. (В документах по VM/370 это описано явно.) В современных системах предпочитают двухэтапную трансляцию. В x86 это EPT, которая действует на адреса от гостя отдельно от хозяйского процесса. В ARM, RISC-V напрямую два этапа трансляции через разные каталоги, но пространство то же, что у хозяйского процесса. Чтобы не дёргаться с shadow paging, лучше сразу, чтобы процессор знал про виртуализацию. А тогда ничего не мешает сделать вообще поддержку процессором понимания разделения между хозяйским и гостевым уровнем.
А вот shadow paging сильно начинает бить по производительности, если не поддержана паравиртуализацией.
MVT как гостевая работала, по ощущениям, так же быстро, как и на реальной машине
Потери там таки должны быть именно на формировании теневых страниц по каждому чиху.
Скажем, таблица сегментов (второй снизу уровень -- и верхний в Системе 370) может указывать не на начало таблицы страниц, а задавать сразу положение всего сегмента в физической памяти -- тем самым избавляя от нужды иметь таблицу страниц в случае, если сегмент всегда отображается или не отображается целиком.
В x86, RISC-V и прочих той же конструкции - "не отображается целиком" было с самого начала (и странно было бы если б сделали иначе). А вот "всегда отображается" представлено в x86 в виде superpages (2MB или 4MB) или hugepages (1GB); 4MB появились с PSE36, 2MB и 1GB страницы - с PAE. Оно используется относительно мало, я видел массовое использование только в HPC приложениях, где хотят исключить затраты на трэшинг TLB (кэша страничной адресации) на каждую маленькую страницу. (В типовом процессоре x86 несколько тысяч записей в TLB. Например, если 1024, как пишут для Haswell, то это только 4MB на минимальных страницах. А там нормально иметь матрицы на гигабайты. Страницы усиленного размера резко сокращают тут затраты на эти поиски.)
Что за "весь сегмент" в 370, я не понял. Если весь адрес в 24 или 31 бит, а корневой каталог покрывает 32 бита, то перемещать сегмент с нулевого адреса больше некуда.
Есть мой перевод последней редакции "Принципов работы Системы 370".
Спасибо. Ну мне перевод с английского не требуется, а вот то, что это чистый справочник, и не даёт типовых или рекомендованных примеров такого применения - даёт, что это существенно не то.
(Хотя вот открыл и увидел ваши примечания на некоторых страницах... это может быть существенно.)
Ну а сделано это для серверов приложений -- и получило дальнейшее углубление и развитие в ESA/370, ESA/390 и z/Architecture.
Спасибо. Не то чтобы стало понятнее, но подтверждение подскажет, куда смотреть дальше...
Но вот пропускная способность системы ввода-вывода у неё сильно выше по сравнению с "шинными" архитектурами вроде PDP-11 и VAX-11. Причём замечу, что даже появление Massbus (лет через 10, если не больше, после появления интерфейса ввода-вывода Системы 360) эту проблему не решил, а лишь снизил.
Тут рядом уже обсуждалось, и я думаю, что эти машины в принципе не предполагали тут настолько серьёзного ускорения - потому что стоило бы сразу резко больше.
Ну и виртуализация, да. По сути, гипервизору (монитору виртуальных машин) можно вообще ничего не знать про периферийное устройство, если с ним умеет работать гостевая ОС -- ему достаточно знать адрес этого устройства, и всё. Любые запросы гостевой ОС он корректирует в плане адресов памяти и адреса устройства
Это если трансляция 1:1 на внешнее устройство или на его часть (в стиле LPAR). Но часто требуется логика посерьёзнее.
Потому VM/370 и её последователи так и остались непревзойдёнными в плане технического качества виртуализации.
Вот тут вопрос, насколько это зависит от формата запросов ввода-вывода, а насколько от того, что гостевые системы помогают в виртуализации.
Ну а на IA-32, как известно, из-за кривизны архитектуры без специальной аппаратной поддержки, появившейся лишь очень поздно, виртуальные машины были вообще невозможны
Это разные вопросы. Сделать в IA-32 полное соответствие входным условиям виртуализации в виде классического Попека-Гольдберга было банально, это один вопрос (добавили бы флажок в регистр) - а вот текущий подход с теневыми регистрами и двухуровневым DAT сильно меньше требует паравиртуализации, было достаточной причиной, чтобы его вводить.
Я участвовал в проекте с работой с 3GPP протоколами, нормальном проприетарном "галерном" проекте. Именно PER был основным страшилищем. Формально там всё хорошо, конечно, но на практике получалась масса проблем с отсутствием средств диагностики сериализации и десериализации сообщений. Возможно, где-то есть высококачественные проприетарные, нам они не достались. В реально же доступном наборе были или такие, которые умели нужные спецификации включая параметризованные ASN.1 схеме, но по принципу "всё или ничего" - или пакет разбирается, или нет, или такие, которые умели показывать все детали разбора согласно приложенной схеме, но при этом содержали невычищенные ошибки. Разбор даже небольшого 100-байтного пакета какого-нибудь XNAP превращался в дёргание между такими средствами и ручной разбор по битам. Это было не последней причиной, почему я оттуда сбежал.
Ситуация усугублялась тем, что формально у 3GPP обратная совместимость, но реально в спецификациях периодически возникало "ой, мы тут диапазон расширили и заодно бит расширения на будущее добавили".
Ваши схемки красивы и чудесны тут, но они не показывают даже малую часть той внутренней боли.
Я понимаю причину введения PER после многословности BER, но цена за неё великовата. Кстати, тут соотношение не всегда строго в пользу PER. Представим себе integer, который обычно не выходит за 100, но иногда может достичь триллионов. Я видел такие случаи. В BER кодирование будет предельно компактным - 2 лишних байта, а дальше само значение в минимуме. В PER тут вот фиксировано 6 байт, 6 и передавай, если такой размах в принципе возможен. (Да, кто-то сделает в таком случае схему с передачей большого значения через расширение. Но это уже костыль.)
В этом смысле меня больше радует CBOR. Упаковка в первый байт базового типа, значения (если влезло) или длины - даёт, конечно, толще выхлоп, чем идеализированный "в сферическом вакууме" PER, но сильно меньше, чем BER, и ещё и сам по себе не требует схемы для получения общей структуры. Жаль, что его так поздно изобрели и мало применяют.
Контроллер в PC, в отличие от канала мейнфрейма, не может же выполнять DMA в обход PCI.
Ваше предложение неуместно. "Контроллер канала мейнфрейма" должен так или иначе получать доступ к памяти. Значит, между ними есть какая-то шина (группа шин). Это аналог PCI (любого PCI) для архитектуры на нём, и вопрос в организации и производительности одной конкретной шины, а не в общем принципе.
Детали зависят уже от того, как эта шинная структура организована. И тут нет причин фиксироваться именно на PCI. Тот же Infiniband используется в некоторых ну очень продвинутых версиях (и PCI формально бегает поверх него).
На поздней Системе 370 появился механизм двойного адресного пространства (впоследствии расширен до множества адресных пространств), что резко упрощает и ускоряет реализацию программ-серверов, обслуживающих программы-клиенты. Без этого механизма вызов подпрограммы в сервере надо производить через ядро ОС, с ним -- можно вызывать прямо, при этом привилегии у клиента и сервера разные, но всё контролируется и защищено
О, вот это интересно. В "Principles of operation" куча технических подробностей, но как начнёшь читать про все эти ASTEIN, так шарики за ролики заезжают и сложно понять, кому и как это вообще было нужно. Явно же не для простой виртуализации.
Это хорошая тема для отдельной статьи. Или уже есть где-то популярное описание, как это строилось и работало?
По вводу-выводу VAX сильно уступает -- как уступает и любая современная архитектура (попробуй подключить к ПК -- именно к ПК, не по локалке, -- тысячи дисков, и чтоб оно ещё и летало, -- ну а к мэйнфрейму z/Architecture -- запросто, если у тебя есть деньги на эти тысячи дисков :) ).
Нетъ. Представим себе чуть другую реализацию для S/360: что там бы использовалось отображение на память, и, например, вместо SIO было бы: проверить слово по адресу CB (channel base), что он ещё может принять одну команду; записать в CB+4 адрес первой CCW, в CB+8 адрес устройства, и в CB+12 константу 1 (SIO), а дальше канал исполняет работу сам. Отличалось бы это по эффективности от команды SIO процессора? Безусловно, нет.
И именно этот подход, с точностью до маппинга значений и адресов, используется сейчас в контроллерах NVMe, AHCI, разных USB хостах, продвинутых сетевухах (да даже NE2000 уже сама делала ввод-вывод), в общем, в любом лаптопе x86 это в полный рост. Ещё раньше - в SCSI контроллерах, на которых уже в 80-х держали десятки дисков в корзинах.
Главное - чтобы скорости всех промежуточных участников, типа системной шины, хватало на это.
Так что насчёт "уступает и любая современная архитектура (попробуй подключить к ПК -- именно к ПК" вы совершенно неправы. Подключить можно, результат тот же - и он реально достигается в достаточно толстых серверах. Просто смысла реально нет на один сервер подключить тысячу дисков. А вот один и чтобы с SSD туда-обратно одновременно ходило до 256 (реально) или до 65536 (ни один контроллер не умеет, но тег на NVMe - 16 бит) операций и чтобы диск их отрабатывал впараллель, как ему удобно - это в полный рост.
А на PDP-11, VAX и прочих это не делали именно потому, что не было возможности впихнуть полный набор подобных средств в доступные ресурсы, в отличие от. Но дисковые контроллеры с собственным DMA - делали. А когда в PCI ввели возможность bus mastering для каждого устройства, стало понятно, что и для уровня PC это пришло.
Метод с канальными программами и командами управления типа SIO (SXCH) - хорош, конечно, для работы из виртуальной машины, не нужно отслеживать каждую операцию с регистрами устройства в MMIO. Но можно и устройство сделать так, чтобы виртуализировалось без проблем - и это сейчас делают, например, в Infininiband контроллерах, выделяя по странице DAT на подустройство.
Зато через канальные программы неудобно делать некоторые другие вещи. Например, почему-то:) в этой линии таймеры сделаны через память или через отдельные команды процессора. Или вот ожидание прихода данных с сетевого адаптера: это означает в канальной архитектуре запустить операцию чтения и она может неопределённое время (секунды и больше) висеть в ожидании чуда. Это поэтому в S/370 сделали много "субканалов" на устройство? По сути таки костыль.
Скажем, у современных ARMов единственное, что от идеологии RISC осталось, -- это отсутствие команд, прямо обрабатывающих данные в памяти, все остальные атрибуты они утратили: есть сложные команды, выполняемые несколько тактов, команды имеют разную длину (система команд Thumb), декодирование стало весьма нетривиальным...
AArch64 вернулся к фиксированной длине команд, Thumb остался в 32 битах. (В среднем код толще аналогичного для x86 на 1-2%.)
Большинство команд стараются оставить в пределах одного такта, при этом вводя много хитрых приёмов (например, см. CSEL семейство - трюк практически гениальный, или как BFM семейство забрало на себя все сдвиги на константную ширину).
Прямая обработка в памяти существует для атомарных операций. В 8.0 архитектуре их не было, было LR/SC (LDXR, STXR), но обнаружили, что у них этот метод отвратительно масштабируется на много процессоров, с 8.1 ввели compare-and-set и аналогичные для операций AND/OR/ADD/etc.
Флаги NZVC есть, но у большинства команд есть варианты, которые не ставят эти флаги, если не нужно. У многих вообще варианта нет поставить флаги (местами, я думал, перестарались - как для SDIV, где детект ситуаций типа MIN/-1 средствами процессора был бы очень полезен).
В целом я бы сказал, что ARM тут очень хорошо держат баланс, отходя от чистой RISC идеологии только там, где без этого будет существенная потеря в чём-то.
Если память не изменяет, в VAX разделение памяти на 2 нижних гига и 2 верхних навязывалось архитектурой
Да, у VAX принципиально четыре квадранта, один в резерве, один для супервизора (ОС), таблицы у них различны. Их можно менять по частям.
И, кстати, вот это как раз лучше чем то, что в x86, S/370, RISC-V и прочих, где таблица одна на всех (ну, у S/370 другие факторы могут смягчать?) Трансляция области супервизора в общей памяти обычно поддерживается одинаковой на все процессы. При этом, если в корневом каталоге меняются записи нижележащих каталогов, надо их менять для всех процессов. Часто это оставляют на момент переключения процессов, держа учёт поколения этого подсписка каталогов. Это не сложно - один раз написать - но громоздко. У AArch64 два каталога страниц, на нижнюю и верхнюю область, но граница между ними регулируется, а не жёсткая, как у VAX.
Ещё у VAX плохо было сделано, что нет иерархии каталогов, а вместо этого на каждый квадрант один плоский каталог. Толстые процессы вследствие этого было сложно расширять, могло оказаться, что нет связного куска памяти для каталога пошире.
Мне тогда казалось что СМ PDP красива, особенно система команд, а ЕС IBM урод и там много костылей.
Мне в детстве тоже казалось, что у PDP-11 идеальная система команд ("в детстве" это не полемическая форма, я с ними столкнулся в ~14 лет). Впоследствии с опытом пришло видение, сколько там было явно сомнительных решений, например:
Отсутствие идеи про расширение команд на второе слово, если нужно (на поздних этапах там возникла давка в кодах вокруг FPP и тому подобного).
Вынос некоторого ограниченного количества операций в наиболее "широкий" по свойствам набор (ccssdd₈), забив пространство кодов - даже на XOR не осталось, она уже попала в урезанный набор.
Тупейшая реализация ADC и SBC: без громоздких костылей работать более чем с 2-словными числами невозможно, получается, как будто их вообще нет. Последующие версии (как ADC/SBB в x86, ALC/SLC в S/390) в этом смысле умнее, и, главное - очевидно сделаны прямо и без извращений. Совершенно непонятно, зачем в PDP-11 было такое.
MOV которое ставит флаги согласно значению. Во всех последующих уровнях хотя бы "мини" не повторялось. (Даже 6502 их меняет на LDA, но не на STA.)
Минимально используемый (я видел только в шутках) 5-й тип адресации, @-(Rn). В VAX его поэтому убили. Можно было зарезервировать под расширения.
8KB страницы для DAT - неэффективно. Даже возможность размещать их не на естественных границах не очень помогает. Странно, почему не сделали их 4KB или 2KB. Похоже, решили "меньше 8 нельзя, но сэкономим".
Разумеется, всё это "послезнание" - я не представляю себе обстановку конца 60-х, о чём тогда и как думали. Вероятно, просто не было толком опыта, чем эти решения плохи.
Из гениальных решений в ней это однозначно схема флагов NZVC. Её автору надо поставить памятник.
Думаю, основная "человеческая" критика S/360 видя PDP-11 это проблема костылей на некоторых наиболее неприятных операциях типа загрузки полных констант и дальней адресации. Если бы, например, в S/360 сразу сделали команду типа IILF от z/Arch (6-байтная, 32-битная константа целиком в регистр) и/или адресацию от PC (например, сделав правило "регистр 8 как база заменяется на адрес текущей команды") - уже половина плачей ушла бы. Сюда же, вероятно, сделать знаковыми непосредственные смещения в RX и RS командах (IBM это сделала позже в Y-подтипе команд, там 20 бит со знаком), опять же, в других ISA везде со знаком.
Сильно позже придумали реализацию без стирания. В википедии она упомянута с достаточными для физика деталями. Но в изделия она пошла очень мало где - успели прийти микросхемы памяти.
Хм, по-моему, оно становится тривиально понятным, если разобраться, что же вообще происходит с историей и почему она редактируется именно в виде последовательности патчей. Дальше начинает влиять собственно объективная сложность процесса - которая тут может быть достаточно заметна и от которой хотят уйти те, кто просто хотят думать по принципу "вот это состояние работает, а дальше мне лень".
То же самое. Да, тут надо наперёд сообразить, где делить, и какой командой затем получить изменения для деления. `git status` помогает найти следующий коммит, в стиле:
а git restore - применить его изменения без коммита. А затем разобраться, какую именно часть действий вложить в индекс - вот тут можно запутаться, если оно слишком перемешано. Увы.
Это "вручную разобраться" это одна команда stash (можно добавить -a, чтобы вообще всё вкинуло в сохранение). Ну или коммит всего. И то требуется, если надо получить дерево состояния того же мастера, а не просто список коммитов - для последнего и переключаться не надо. Объективно, два разных файловых дерева не могут лежать в одном каталоге, или вы не согласны? Кстати, не помню названия, но для быстрого переключения всем деревом был плагин с компактными командами.
Ну так для них есть автомат, который запускает gc через какой-то объём действий.
Хм, я не очень любитель читать документацию, но, по-моему, там совершенно тривиально. Что именно в этом можно не понять?
Если и так, то они минимально связаны конкретно с Git.
Mercurial успешнее, чем Git, изображает то, что реально нужно ≈90 процентам пользователей - использовать распределённую VCS как централизованную, при этом получая некоторые фишки распределённости в виде временного (долго всё равно не нужно) сохранения коммита (changeset, в терминах Mercurial) у локального пользователя. Полные фишки Git всё равно мало кто использует, слово index уже пугает значительную часть пользователей, а rebase вообще аватарой аццкого сотоны в пределах рабочей копии. В эту сторону работают такие фишки, как последовательная нумерация ченжсетов, вписывание имени текущей ветки в метаданные коммита, и тот же отказ от индекса, который требует других, сильно более топорных инструментов, но при этом визуально более наглядных.
В чём-то я их понимаю - я тоже раз пять делал - "git diff" - "что??? где мои правки???" - "git status" - "ааа блин, они в индексе, смотрим git dc (алиас у меня такой)", и пока не научился делать какой-нибудь "git rebase --abort" и вообще внимательно читать вывод git status, пару раз таки делал как на xkcd нарисовано - убить рабочую копию, стянуть с нуля и сделать заново. Сейчас уже не делаю, но это потому, что я понимал, что если ничего не получается, надо прочесть внимательно ;)
Бранчи в Hg организованы сложно. Если сравнивать с Git.
Сами авторы Hg пишут в документации, что «The term branch is sometimes used for slightly different concepts. This may be confusing for new users of Mercurial.» - прямая цитата из родной вики. В Hg понятие ветки это смешение нескольких разнородных сущностей в одну не сильно приятную (именно из-за смешения) кашу:
1. «Голова» процесса развития, которых может быть несколько в пределах одной рабочей копии или «ветки» в другом понимании. При операциях push, pull передаются все эти головы. В некоторых местах это называется напрямую словом head.
2. Некий установленный локальным режимом тег под названием «branch», который приклеивается к каждому новому changesetʼу, и больше ничего не делает. Именно его чаще всего называют «веткой».
3. Полный пучок п.1, между которыми тоже можно переключаться (множественные головы, которые используются ничтожной частью пользователей, но которые всем надо учитывать).
4. Bookmarks, которые тоже ветки, аналогично Git, но не получили такое имя из-за намеренного отказа разработчиков.
После этого в Git всё тривиально. А основную обиду большинства сторонников Mercurial получает то, что нет автомата, который пишет название локальной ветки-2 при коммите в атрибуты коммита. В Git это решается явной записью в сообщение коммита, причём чаще всего не в виде ветки, а в виде тикета, под который идёт разработка.
На остальное уже ответили в ветке обсуждения.
А при чём тут вообще быть системным программистом к пониманию того, что любое изменение что-то делает в составе файлов и/или в их содержании? Это уровень простого юзера ПК, даже не программиста.
Кажется, слишком много коней и людей смешались в одной куче.
В Git получить патч между коммитами-снапшотами не просто, а очень просто. Но любой патч будет содержать контекстно-зависимые данные - например, номера строк. Пусть в ветке v12 перед местом патча добавили 30 строк. Патч для v12 будет начинаться со строки 199, а для v11 начинался со 169. Это один и тот же патч, или разные? А если со 169 другое место для применения с тем же контекстом (патч ложится ровно)?
Не влияет.
Не становится. Те же проблемы наложения при изменении контекста.
Не влияет.
Если стало работать лучше, то изменено что-то в этом самом методе автоматического разрешения конфликтов, а не в базе самого движка.
И вот это интересно - может быть применено везде.
То, что вам показывают в формате git log -p или аналога дифф в случае одного родителя - оптимизация усилий на типовой случай. Уже при merge это не показывается, надо явно запрашивать.
Хохму с дракой за спинлоки я помню ещё в районе 2000 года. Сервер БД для хостинга поставили на MySQL на Linux, и увидели, что если в локи входят несколько одновременно клиентов, то их процессы начинают только и делать, что крутиться в ожидании освобождения, и в результате зависимость квадратичная от количества вошедших. Лечить это в коде мы тогда не могли, и мистическим образом улучшение настало от перевода на FreeBSD, где треды были сделаны на libc_r, старой и кривоватой, которая реально один системный процесс с переключением в юзерленде - и это работало лучше! Исправление наступило года через два с новыми версиями всего.
Реально такие нелинейные росты это основная проблема любой загрузки чего-то.
Ну почему же. Они говорили, что машина годится одновременно для математических, экономических и управляющих задач - чем не 360 градусов? ;) Ну при этом ещё и домен realtime они, скорее всего, просто не предполагали.
Тут согласен на 300%, количество и специфику странных решений у них можно обсуждать часами.
У x86 этому не хватало буквально ограничения нескольких команд (SMSW, SIDT, STR, ещё какой-то, точно не помню). Вполне можно было поставить на них дополнительное ограничение, и получилось бы примерно так же.
Но тут вступает в силу следующий фактор. Виртуализация классического стиля Попек-Голдберг предполагает, что хозяйская система ведёт теневые страницы механизма DAT, иначе не может справиться с трансляцией. (В документах по VM/370 это описано явно.) В современных системах предпочитают двухэтапную трансляцию. В x86 это EPT, которая действует на адреса от гостя отдельно от хозяйского процесса. В ARM, RISC-V напрямую два этапа трансляции через разные каталоги, но пространство то же, что у хозяйского процесса. Чтобы не дёргаться с shadow paging, лучше сразу, чтобы процессор знал про виртуализацию. А тогда ничего не мешает сделать вообще поддержку процессором понимания разделения между хозяйским и гостевым уровнем.
А вот shadow paging сильно начинает бить по производительности, если не поддержана паравиртуализацией.
Потери там таки должны быть именно на формировании теневых страниц по каждому чиху.
Она к ней уже должна быть готова.
В x86, RISC-V и прочих той же конструкции - "не отображается целиком" было с самого начала (и странно было бы если б сделали иначе). А вот "всегда отображается" представлено в x86 в виде superpages (2MB или 4MB) или hugepages (1GB); 4MB появились с PSE36, 2MB и 1GB страницы - с PAE. Оно используется относительно мало, я видел массовое использование только в HPC приложениях, где хотят исключить затраты на трэшинг TLB (кэша страничной адресации) на каждую маленькую страницу. (В типовом процессоре x86 несколько тысяч записей в TLB. Например, если 1024, как пишут для Haswell, то это только 4MB на минимальных страницах. А там нормально иметь матрицы на гигабайты. Страницы усиленного размера резко сокращают тут затраты на эти поиски.)
Что за "весь сегмент" в 370, я не понял. Если весь адрес в 24 или 31 бит, а корневой каталог покрывает 32 бита, то перемещать сегмент с нулевого адреса больше некуда.
Спасибо. Ну мне перевод с английского не требуется, а вот то, что это чистый справочник, и не даёт типовых или рекомендованных примеров такого применения - даёт, что это существенно не то.
(Хотя вот открыл и увидел ваши примечания на некоторых страницах... это может быть существенно.)
Спасибо. Не то чтобы стало понятнее, но подтверждение подскажет, куда смотреть дальше...
Тут рядом уже обсуждалось, и я думаю, что эти машины в принципе не предполагали тут настолько серьёзного ускорения - потому что стоило бы сразу резко больше.
Это если трансляция 1:1 на внешнее устройство или на его часть (в стиле LPAR). Но часто требуется логика посерьёзнее.
Вот тут вопрос, насколько это зависит от формата запросов ввода-вывода, а насколько от того, что гостевые системы помогают в виртуализации.
Это разные вопросы. Сделать в IA-32 полное соответствие входным условиям виртуализации в виде классического Попека-Гольдберга было банально, это один вопрос (добавили бы флажок в регистр) - а вот текущий подход с теневыми регистрами и двухуровневым DAT сильно меньше требует паравиртуализации, было достаточной причиной, чтобы его вводить.
Я участвовал в проекте с работой с 3GPP протоколами, нормальном проприетарном "галерном" проекте. Именно PER был основным страшилищем. Формально там всё хорошо, конечно, но на практике получалась масса проблем с отсутствием средств диагностики сериализации и десериализации сообщений. Возможно, где-то есть высококачественные проприетарные, нам они не достались. В реально же доступном наборе были или такие, которые умели нужные спецификации включая параметризованные ASN.1 схеме, но по принципу "всё или ничего" - или пакет разбирается, или нет, или такие, которые умели показывать все детали разбора согласно приложенной схеме, но при этом содержали невычищенные ошибки. Разбор даже небольшого 100-байтного пакета какого-нибудь XNAP превращался в дёргание между такими средствами и ручной разбор по битам. Это было не последней причиной, почему я оттуда сбежал.
Ситуация усугублялась тем, что формально у 3GPP обратная совместимость, но реально в спецификациях периодически возникало "ой, мы тут диапазон расширили и заодно бит расширения на будущее добавили".
Ваши схемки красивы и чудесны тут, но они не показывают даже малую часть той внутренней боли.
Я понимаю причину введения PER после многословности BER, но цена за неё великовата. Кстати, тут соотношение не всегда строго в пользу PER. Представим себе integer, который обычно не выходит за 100, но иногда может достичь триллионов. Я видел такие случаи. В BER кодирование будет предельно компактным - 2 лишних байта, а дальше само значение в минимуме. В PER тут вот фиксировано 6 байт, 6 и передавай, если такой размах в принципе возможен. (Да, кто-то сделает в таком случае схему с передачей большого значения через расширение. Но это уже костыль.)
В этом смысле меня больше радует CBOR. Упаковка в первый байт базового типа, значения (если влезло) или длины - даёт, конечно, толще выхлоп, чем идеализированный "в сферическом вакууме" PER, но сильно меньше, чем BER, и ещё и сам по себе не требует схемы для получения общей структуры. Жаль, что его так поздно изобрели и мало применяют.
Ваше предложение неуместно. "Контроллер канала мейнфрейма" должен так или иначе получать доступ к памяти. Значит, между ними есть какая-то шина (группа шин). Это аналог PCI (любого PCI) для архитектуры на нём, и вопрос в организации и производительности одной конкретной шины, а не в общем принципе.
Детали зависят уже от того, как эта шинная структура организована. И тут нет причин фиксироваться именно на PCI. Тот же Infiniband используется в некоторых ну очень продвинутых версиях (и PCI формально бегает поверх него).
Вы криво прочли. На SCSI шине, например, связь каждого "канала" (контроллера) с устройствами своя, там уже нет общего PCIe.
О, вот это интересно. В "Principles of operation" куча технических подробностей, но как начнёшь читать про все эти ASTEIN, так шарики за ролики заезжают и сложно понять, кому и как это вообще было нужно. Явно же не для простой виртуализации.
Это хорошая тема для отдельной статьи. Или уже есть где-то популярное описание, как это строилось и работало?
Нетъ. Представим себе чуть другую реализацию для S/360: что там бы использовалось отображение на память, и, например, вместо SIO было бы: проверить слово по адресу CB (channel base), что он ещё может принять одну команду; записать в CB+4 адрес первой CCW, в CB+8 адрес устройства, и в CB+12 константу 1 (SIO), а дальше канал исполняет работу сам. Отличалось бы это по эффективности от команды SIO процессора? Безусловно, нет.
И именно этот подход, с точностью до маппинга значений и адресов, используется сейчас в контроллерах NVMe, AHCI, разных USB хостах, продвинутых сетевухах (да даже NE2000 уже сама делала ввод-вывод), в общем, в любом лаптопе x86 это в полный рост. Ещё раньше - в SCSI контроллерах, на которых уже в 80-х держали десятки дисков в корзинах.
Главное - чтобы скорости всех промежуточных участников, типа системной шины, хватало на это.
Так что насчёт "уступает и любая современная архитектура (попробуй подключить к ПК -- именно к ПК" вы совершенно неправы. Подключить можно, результат тот же - и он реально достигается в достаточно толстых серверах. Просто смысла реально нет на один сервер подключить тысячу дисков. А вот один и чтобы с SSD туда-обратно одновременно ходило до 256 (реально) или до 65536 (ни один контроллер не умеет, но тег на NVMe - 16 бит) операций и чтобы диск их отрабатывал впараллель, как ему удобно - это в полный рост.
А на PDP-11, VAX и прочих это не делали именно потому, что не было возможности впихнуть полный набор подобных средств в доступные ресурсы, в отличие от. Но дисковые контроллеры с собственным DMA - делали. А когда в PCI ввели возможность bus mastering для каждого устройства, стало понятно, что и для уровня PC это пришло.
Метод с канальными программами и командами управления типа SIO (SXCH) - хорош, конечно, для работы из виртуальной машины, не нужно отслеживать каждую операцию с регистрами устройства в MMIO. Но можно и устройство сделать так, чтобы виртуализировалось без проблем - и это сейчас делают, например, в Infininiband контроллерах, выделяя по странице DAT на подустройство.
Зато через канальные программы неудобно делать некоторые другие вещи. Например, почему-то:) в этой линии таймеры сделаны через память или через отдельные команды процессора. Или вот ожидание прихода данных с сетевого адаптера: это означает в канальной архитектуре запустить операцию чтения и она может неопределённое время (секунды и больше) висеть в ожидании чуда. Это поэтому в S/370 сделали много "субканалов" на устройство? По сути таки костыль.
AArch64 вернулся к фиксированной длине команд, Thumb остался в 32 битах. (В среднем код толще аналогичного для x86 на 1-2%.)
Большинство команд стараются оставить в пределах одного такта, при этом вводя много хитрых приёмов (например, см. CSEL семейство - трюк практически гениальный, или как BFM семейство забрало на себя все сдвиги на константную ширину).
Прямая обработка в памяти существует для атомарных операций. В 8.0 архитектуре их не было, было LR/SC (LDXR, STXR), но обнаружили, что у них этот метод отвратительно масштабируется на много процессоров, с 8.1 ввели compare-and-set и аналогичные для операций AND/OR/ADD/etc.
Флаги NZVC есть, но у большинства команд есть варианты, которые не ставят эти флаги, если не нужно. У многих вообще варианта нет поставить флаги (местами, я думал, перестарались - как для SDIV, где детект ситуаций типа MIN/-1 средствами процессора был бы очень полезен).
В целом я бы сказал, что ARM тут очень хорошо держат баланс, отходя от чистой RISC идеологии только там, где без этого будет существенная потеря в чём-то.
Да, у VAX принципиально четыре квадранта, один в резерве, один для супервизора (ОС), таблицы у них различны. Их можно менять по частям.
И, кстати, вот это как раз лучше чем то, что в x86, S/370, RISC-V и прочих, где таблица одна на всех (ну, у S/370 другие факторы могут смягчать?) Трансляция области супервизора в общей памяти обычно поддерживается одинаковой на все процессы. При этом, если в корневом каталоге меняются записи нижележащих каталогов, надо их менять для всех процессов. Часто это оставляют на момент переключения процессов, держа учёт поколения этого подсписка каталогов. Это не сложно - один раз написать - но громоздко. У AArch64 два каталога страниц, на нижнюю и верхнюю область, но граница между ними регулируется, а не жёсткая, как у VAX.
Ещё у VAX плохо было сделано, что нет иерархии каталогов, а вместо этого на каждый квадрант один плоский каталог. Толстые процессы вследствие этого было сложно расширять, могло оказаться, что нет связного куска памяти для каталога пошире.
Мне в детстве тоже казалось, что у PDP-11 идеальная система команд ("в детстве" это не полемическая форма, я с ними столкнулся в ~14 лет). Впоследствии с опытом пришло видение, сколько там было явно сомнительных решений, например:
Отсутствие идеи про расширение команд на второе слово, если нужно (на поздних этапах там возникла давка в кодах вокруг FPP и тому подобного).
Вынос некоторого ограниченного количества операций в наиболее "широкий" по свойствам набор (ccssdd₈), забив пространство кодов - даже на XOR не осталось, она уже попала в урезанный набор.
Тупейшая реализация ADC и SBC: без громоздких костылей работать более чем с 2-словными числами невозможно, получается, как будто их вообще нет. Последующие версии (как ADC/SBB в x86, ALC/SLC в S/390) в этом смысле умнее, и, главное - очевидно сделаны прямо и без извращений. Совершенно непонятно, зачем в PDP-11 было такое.
MOV которое ставит флаги согласно значению. Во всех последующих уровнях хотя бы "мини" не повторялось. (Даже 6502 их меняет на LDA, но не на STA.)
Минимально используемый (я видел только в шутках) 5-й тип адресации,
@-(Rn)
. В VAX его поэтому убили. Можно было зарезервировать под расширения.8KB страницы для DAT - неэффективно. Даже возможность размещать их не на естественных границах не очень помогает. Странно, почему не сделали их 4KB или 2KB. Похоже, решили "меньше 8 нельзя, но сэкономим".
Разумеется, всё это "послезнание" - я не представляю себе обстановку конца 60-х, о чём тогда и как думали. Вероятно, просто не было толком опыта, чем эти решения плохи.
Из гениальных решений в ней это однозначно схема флагов NZVC. Её автору надо поставить памятник.
Думаю, основная "человеческая" критика S/360 видя PDP-11 это проблема костылей на некоторых наиболее неприятных операциях типа загрузки полных констант и дальней адресации. Если бы, например, в S/360 сразу сделали команду типа IILF от z/Arch (6-байтная, 32-битная константа целиком в регистр) и/или адресацию от PC (например, сделав правило "регистр 8 как база заменяется на адрес текущей команды") - уже половина плачей ушла бы. Сюда же, вероятно, сделать знаковыми непосредственные смещения в RX и RS командах (IBM это сделала позже в Y-подтипе команд, там 20 бит со знаком), опять же, в других ISA везде со знаком.
Сильно позже придумали реализацию без стирания. В википедии она упомянута с достаточными для физика деталями. Но в изделия она пошла очень мало где - успели прийти микросхемы памяти.