Мы стремимся сделать процесс внесения вклада в этот проект максимально простым и прозрачным.
Новые версии создаются в ветке "dev", либо в отдельной функциональной ветке. Когда они считаются готовыми для выпуска, они сливаются в ветку "release".
Как следствие, все вклады должны проходить через ветку "dev" или их собственную функциональную ветку.
Мы активно приветствуем ваши пулл-запросы.
dev
.Чтобы принять ваш пулл-запрос, нам требуется, чтобы вы представили Договор о лицензии на вклад ("CLA"). Вам потребуется это сделать всего один раз для работы над любыми открытыми проектами компании Facebook.
Заполните ваш "CLA" здесь: https://code.facebook.com/cla
Проект Zstd использует ветвной подход для изменения кодовой базы. Обычно Zstd будет использовать новую ветку для каждого значительного темы. Для небольших изменений можно объединять несколько связанных изменений в одну ветку.
Наши процессы вклада работают в трех основных этапах:
git checkout https://github.com/<username>/zstd
cd zstd
git pull https://github.com/facebook/zstd dev
git push origin dev
# Имена веток должны быть краткими, но достаточно информативными
git checkout -b <branch-name>
git push origin <branch-name>
# выполните некоторые изменения =
git add -u && git commit -m <сообщение>
git push origin <branch-name>
make check
make test
scan-build make -C contrib/largeNbDicts largeNbDicts
scan-build
является частью нашей регулярной системы CI. Другие статические анализаторы не используются постоянно.
Иногда полезно смотреть на дополнительные статические анализаторы, но множить количество анализаторов, выполняемых при каждом коммите и пулл-запросе, не лучшая идея. Причины:- Статические анализаторы часто содержат большое количество ложноположительных сигналов. Соотношение сигналов к шуму довольно низкое.
Это отличается от выполнения статического анализа время от времени, просмотра вывода и выборочного использования некоторых предупреждений, которые кажутся полезными, поскольку они действительно указывают на риск ошибки или способствуют более понятному и менее подверженному злоупотреблению коду. Такие отчёты полезны и принимаются.
Тесты CI выполняются каждый раз, когда создаётся или обновляется пулл-запрос. Конкретные тесты, которые выполняются, зависят от целевой ветки, которую вы указываете. Некоторые тесты занимают больше времени, чем другие. В настоящее время наша система CI настроена на выполнение короткой серии тестов при создании пулл-запроса к ветке dev и длинной серии тестов при создании пулл-запроса к ветке release. Вы можете найти информацию о том, что выполняется, в конфигурационных файлах соответствующего сервиса CI.
Большинство людей просто хотят создать пулл-запрос с целевой веткой, равной их локальной ветке dev Zstd. Вы можете затем найти статус тестов на странице пулл-запроса. Также вы можете повторно запустить тесты и отменить запущенные тесты с помощью страницы пулл-запроса или панели управления соответствующего сервиса CI.
практически все CI Zstd выполняются на GitHub Actions (��置在.github/workflows
目录下),这些操作会在您自己的分叉中创建拉取请求时自动运行。少数测试则在其他服务上运行(例如,Travis CI、Circle CI、AppVeyor)。这些需要在您的本地分支上进行设置,并且至少对于Travis CI来说会带来成本。因此,如果您的本地分支上的拉取请求通过了GitHub Actions,请随时提交针对主仓库的拉取请求。
一小部分测试无法在GitHub Actions上执行或尚未迁移。为此情况我们使用不同的第三方服务(见下方表格)。为Zstd贡献而设置这些服务的需求并不强制;然而,我们提供了链接到那些希望获得早期信号的人的说明。
服务 | 目标 | 设置指南 | 配置路径 |
---|---|---|---|
Travis CI | 用于测试非x86架构(如PowerPC)的架构 |
https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci-using-github https://github.com/marketplace/travis-ci |
.travis.yml |
AppVeyor | 用于某些Windows测试(如cygwin、mingw) |
https://www.appveyor.com/blog/2018/10/02/github-apps-integration/ https://github.com/marketplace/appveyor |
appveyor.yml |
Cirrus CI | 用于FreeBSD上的测试 | https://github.com/marketplace/cirrus-ci/ | .cirrus.yml |
Circle CI | 历史上曾被用来提供快速信号,但这些测试可能已经迁移到GitHub Actions中 |
https://circleci.com/docs/2.0/getting-started/#setting-up-circleci https://youtu.be/Js3hMUsSZ2c https://circleci.com/docs/2.0/enable-checks/ |
.circleci/config.yml |
注:上述提供的指南主要涵盖了从零开始配置带有CI的存储库的过程。 对于将CI配置到您自己fork中的Zstd的主要思想应该是相同的,但是您可能需要遵循略有不同的步骤。特别是,请忽略任何与配置文件设置相关的指示(因为Zstd已经在每种服务中都有相应的配置)。
高性能对zstd至关重要,我们只接受那些性能特征和相关折衷经过充分分析、重现并展示的pull请求。这种高标准的要求意味着每个潜在影响性能的pull请求都需要花费大量时间来正确验证。尽管如此,我们总是欢迎旨在提高性能(或降低性能以换取其他优势)的贡献。请在发送与性能相关的pull请求之前注意以下几点:
К сожалению, самым важным аспектом для надежного бенчмаркинга является наличие устойчивой машины для проведения бенчмарков. Виртуальная машина, машина с совместно используемыми ресурсами или ваш ноутбук обычно не будут достаточно устойчивыми для получения надежных результатов бенчмарков. Если вам доступна настольная машина, это обычно лучший вариант.
Конечно, бенчмаркирование можно выполнять и на машинах, не являющихся сверхустойчивыми. Вам просто придется сделать больше работы, чтобы гарантировать, что вы действительно измеряете изменения, а не шум. Вот несколько вещей, которые вы можете сделать, чтобы сделать ваши бенчмарки более устойчивыми:
数量 |---------|
中文 | |
---|---|
样本。它们应该 становиться всё меньше и меньше. Наконец, они должны стать меньше, чем ожидаемый выигрыш производительности。 |
Также обратитесь к руководству LLVM по бенчмаркингу здесь:https://llvm.org/docs/Benchmarking.html
Наиболее быстрым сигналом о ваших изменениях производительности является встроенный zstd cli опция bench。Вы можете запустить Zstd так, как обычно делали бы для вашего случая, используя определённый набор опций, а затем дополнительно указать опцию -b#
。Выполнение этого запустит нашу конвейерную линию бенчмарков для предоставленных вами опций。Если вы хотите посмотреть внутреннюю работу этого бенчмаркового скрипта, вы можете проверить programs/benchzstd.c
Например:предположим, вы внесли изменения, которые считаете улучшающими скорость zstd уровня 1。Первым шагом должно быть использование zstd -b
,чтобы оценить, действительно ли произошло какое-либо улучшение。Вы можете попробовать что-то вроде этого。Примечание:вы можете использовать опцию -i
для указания времени выполнения вашего бенчмарка в секундах(по умолчанию 3 секунды)。Обычно, чем длиннее время выполнения, тем более устойчивыми будут ваши результаты。
$ git checkout <commit-before-your-change>
$ make && cp zstd zstd-old
$ git checkout <commit-after-your-change>
$ make && cp zstd zstd-new
$ zstd-old -i5 -b1 <your-test-data>
1<your-test-data> : 8990 -> 3992 (2.252), 302.6 MB/s , 626.4 MB/s
$ zstd-new -i5 -b1 <your-test-data>
1<your-test-data> : 8990 -> 3992 (2.252), 302.8 MB/s , 628.4 MB/s
```Если ваш выигрыш производительности достаточно велик, чтобы быть заметным вопреки естественному шуму на вашем компьютере, то использование benchzstd одного будет недостаточно для подтверждения влияния ваших изменений. Например, результаты выше показывают, что фактически ничего не изменилось, но могло быть небольшое (<3%) улучшение, которое было затушевано шумом на машине. Так что, если вы не видите значительного улучшения производительности (10-15% постоянно) одним таким методом оценки, это будет недостаточно.
### Профилирование
Существует множество отличных профиллеров. Мы кратко упомянем, как вы можете профилировать свой код с использованием `instruments` на Mac, `perf` на Linux и `Visual Studio Profiler` на Windows.
Предположим, у вас есть идея для изменения, которое вы считаете может предоставить хорошие улучшения производительности для сжатия уровня 1 в zstd. Обычно это значит, что вы определили участок кода, который вы считаете можно сделать более эффективным.
Первым шагом будет убедиться, что данный участок кода действительно занимает значительное время для выполнения. Обычно нет смысла оптимизировать что-то, что составляет менее 0.0001% от общего времени выполнения. К счастью, есть инструменты, которые помогают с этим. Профиллеры позволят вам увидеть, сколько времени ваш код тратит внутри определенной функции. Если ваш целевой кодовый фрагмент является частью функции, может быть полезно попытаться изолировать этот фрагмент, переместив его в свою собственную функцию (обычно это не обязательно, но может быть полезным).
Большинство профиллеров (включая профиллеры, обсуждаемые ниже) сгенерируют для вас граф вызова функций. Ваша цель будет найти интересующую вас функцию в этом графе и затем исследовать время, затраченное внутри неё. Также может быть полезно посмотреть на аннотированный ассемблер, который большинство профиллеров предоставляют.
#### Инструменты
Мы снова рассмотрим ситуацию, где вы считаете, что определили участок кода, производительность которого можно улучшить. Следуйте этим шагам для профилирования вашего кода с использованием инструментов:
1. Откройте инструменты
2. Выберите `Time Profiler` из списка стандартных шаблонов
3. Закройте все остальные приложения, кроме окна с вашими инструментами и терминала
4. Запустите свой скрипт тестирования производительности из терминального окна
* Вам потребуется тест, который будет работать как минимум несколько секунд (5 секунд обычно достаточно). Это позволит профилировщику получить данные для анализа и вам будет достаточно времени, чтобы присоединиться к процессу тестирования.
* Я буду использовать benchzstd в качестве своего скрипта тестирования производительности в этом примере:
$ zstd -b1 -i5 <мои-данные> # это будет выполняться 5 секунд
5. После запуска вашего скрипта тестирования производительности вернитесь обратно к инструментам и присоедините процесс к Time Profiler. Для этого выполните следующие действия:
* Нажмите на выпадающий список `Все процессы` в левом верхнем углу панели инструментов.
* Выберите ваш процесс из выпадающего списка. В моем случае, он будет просто помечен как `zstd`
* Нажмите ярко-красную кнопку записи в левом верхнем углу панели инструментов
6. Ваш профилировщик теперь начнет собирать метрики от вашего скрипта тестирования производительности. Как только вы считаете, что собрали достаточное количество образцов (обычно это происходит после 3 секунд записи), остановите профилировщик.
7. Убедитесь, что в нижней части экрана выбран пункт `профиль`.
8. Вы должны видеть свою диаграмму вызовов.
* Если вы не видите диаграмму вызовов или незавершенную диаграмму вызовов, убедитесь, что вы скомпилировали zstd и ваш скрипт тестирования производительности с использованием флагов отладки. На Mac и Linux это означает, что вам придется предоставить флаг `-g` вместе со своим скриптом сборки. Возможно, вам также придется предоставить флаг `-fno-omit-frame-pointer`.
#### Perf
Этот вики имеет довольно подробное руководство по началу работы с perf, поэтому мы оставляем вас самостоятельно изучать его, если вы начинаете работу:
https://perf.wiki.kernel.org/index.php/Tutorial
Некоторые общие замечания по поводу perf:
* Используйте `perf stat -r # <bench-program>` для быстрого получения некоторых значимых временных и счетчиковых статистик. Perf использует высокоточный таймер, и это, скорее всего, одно из первых вещей, которые ваша команда будет выполнять при оценке вашего запроса.
* Perf имеет длинный список аппаратных счетчиков, которые можно просмотреть с помощью `perf --list`. Когда вы измеряете оптимизации, стоит попробовать убедиться, что те аппаратные счетчики, которые вы ожидаете будут затронуты изменениями, действительно таковыми являются. Например, если вы ожидаете, что число пропущенных запросов к кешу L1 уменьшится благодаря вашим изменениям, вы можете посмотреть на счетчик `L1-dcache-load-misses`
* Аппаратные счетчики perf не будут работать на виртуальной машине.
#### Visual Studio
TODO
## Проблемы
Мы используем GitHub проблемы для отслеживания открытых багов. Пожалуйста, убедитесь, что ваше описание четкое и содержит достаточно инструкций для воспроизведения проблемы.
Facebook имеет программу вознаграждения за безопасное раскрытие уязвимостей безопасности. В этих случаях, пожалуйста, следуйте процедуре, указанной на этой странице, и не создавайте публичную проблему.
## Стиль программирования
Это довольно широкий вопрос, который трудно свести к одному абзацу. По правилу большинства, попытайтесь имитировать стиль программирования аналогичных строк кода рядом с вашим вкладом.
Следующий список правил, применяемых в базе кода zstd, является неполным:
### C90
Эта база кода следует строгому стандарту C90,
с двумя расширениями: типами `long long` 64-битного размера и макросами с переменным количеством аргументов.
Это правило применяется строго к коду внутри `lib/` и `programs/`.
Подпроекты в `contrib/` могут использовать другие соглашения.
### Прямая совместимость C++: манипуляция символов
Все публичные объявления символов должны быть заключены в `extern "C" { ... }`,
чтобы этот проект мог компилироваться как C++98 код,
и связываться с C++ приложениями.### Минимальная экономия
Это требование дизайна важно для сохранения портативности кодовой базы.
#### Зависимости
- Уменьшите зависимости до минимального уровня возможного.
Любая зависимость должна рассматриваться как «плохая» по умолчанию,
и допускаться только потому, что она обеспечивает услугу лучше, чем может быть достигнуто локально.
Единственные внешние зависимости, которые эта репозитория допускает, — это стандартные библиотеки C и системные заголовочные файлы уровнем ниже.
- Внутри `lib/`, данная политика еще более жесткая.
Единственными допустимыми внешними зависимостями являются `<assert.h>`, `<stdlib.h>`, `<string.h>`,
но даже они не используются напрямую.
В частности, никакая функция не должна никогда выделять память на куче напрямую,
и вместо этого должна использовать `ZSTD_malloc()` и эквивалентные функции.
Другие допустимые заголовочные файлы без символов — это `<stddef.h>` и `<limits.h>`.
- В рамках проекта существует строгая иерархия зависимостей, которая должна соблюдаться.
`programs/` может зависеть от `lib/`, но только от его публичного API.
Внутри `lib/`, `lib/common` не зависит ни от одного другого каталога.
`lib/compress` и `lib/decompress` не должны зависеть друг от друга.
`lib/dictBuilder` может зависеть от `lib/common` и `lib/compress`, но не от `lib/decompress`.
#### Ресурсы
- Функции в `lib/` должны использовать очень мало места стека,
максимум нескольких десятков байтов.
Все больше должно использовать аллокатор кучи,
либо требовать рукотворное использование буферов.
### Названия
* Все публичные символы имеют префикс `ZSTD_`
+ Частные символы, область видимости которых ограничивается их собственным модулем, освобождены от данного требования.
Однако, поскольку исходный код `libzstd` может быть объединен,
каждое имя символа должно стремиться быть уникальным и оставаться таким.
Избегайте слишком общих названий, которые могут стать причиной будущего конфликта.
Обычно это означает использование некоторой формы префикса.
* Для символов (функций и переменных), конвенция названия — `PREFIX_camelCase`.
+ В некоторых продвинутых случаях, можно найти:
- `PREFIX_prefix2_camelCase`
- `PREFIX_camelCase_extendedQualifier`
* Многоразрядные названия обычно состоят из действия, последующего объекта:
- Например: `ZSTD_createCCtx()`
* Предпочитайте положительные действия
- `goBackward` вместо `notGoForward`
* Названия типов (`struct`, и т.д.) следуют похожей конвенции,
за исключением того, что они разрешены и даже приглашаются начинаться с заглавной буквы.
Пример: `ZSTD_CCtx`, `ZSTD_CDict`
* Макросы имеют все заглавные буквы.
Те же правила составления (`PREFIX_NAME_QUALIFIER`) применимы.
* Имена файлов состоят из всех строчных букв.
Конвенция — `snake_case`.
Имена файлов **должны** быть уникальными во всей кодовой базе,
даже когда они находятся в явно разделенных директориях.
### Квалификаторы
* Эта база кода дружелюбна к `const`, если не сказать фанатично.
Любая переменная, которую можно сделать `const` (то есть, только для чтения), **должна** быть `const`.
Любой указатель, содержимое которого не будет изменено, должен быть `const`.
Эта характеристика контролируется на уровне компилятора.
`const` переменные являются важным сигналом для читающих, что эта переменная не изменяется.
Соответственно, неконстантные переменные являются сигналом для читающих быть внимательными к возможным изменениям позднее в функции.
* Если функция должна быть встроенной, укажите это явно,
используя собственные переносимые макросы проекта, такие как `FORCE_INLINE_ATTR`,
определенные в `lib/common/compiler.h`.
### Отладка
* **Ассертации** приветствуются, и должны использоваться максимально широко,
чтобы контролировать любое условие, которое код ожидает для корректного выполнения.
Эти проверки ассертаций будут выполняться в режиме отладки и отключены в рабочем режиме.
* Для трассировки, данный проект предоставляет свои собственные макросы отладки,
в частности `DEBUGLOG(уровень, ...)`, определенные в `lib/common/debug.h`.
### Документация кода
* Избегайте документации кода, которая просто повторяет то, что уже заявлено в коде.
Вместо этого, когда применимо, предпочитайте использование кода как основного способа передачи объяснений.
Пример 1: `int nbTokens = n;` вместо `int i = n; /* i is a nb of tokens *./`.
Пример 2: `assert(size > 0);` вместо `/* здесь, size должен быть положительным */`.
* На уровне декларации, документация объясняет, как использовать функцию или переменную,
и когда применимо, почему она нужна, какие сценарии могут быть полезны.
* На уровне реализации, документация объясняет общую структуру алгоритма,
и когда применимо, почему был сделан именно такой выбор.
### Общая структура
* 4 пробела для отступов вместо табуляции
* Документация кода должна немедленно предшествовать объявлению функции или её реализации
* Реализация функции и её документация должны быть отделены пустыми строками
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )