По магистерской ВКР и по работе в последнее время приходится много гуглить и читать статей про то, как ускорять нейронные сети (как на этапе тренировки, так и на этапе использования), в частности в рамках фреймворка Pytorch. 🤓
Вот что было просмотрено быстро глазами и добавлено в заметки на подробное изучение.
⚡️ Как добиться сходимости быстрее. Безусловно, одна из самых важных проблем — нейронные сети обучаются долго (долго сходятся). Есть множество хаков. Одни из них здесь: Тык1, Тык2.
👀 Чтобы ускориться, можно использовать quantization. Это когда мы жертвуем точностью вычисление во благо времени исполнения (не всегда качество страдает). Не всегда такие операции применимы, но в целом если задумались о таком методе — вот неплохой гайд.
👻 Бывает, что вычислительный граф во время обучения нейронной сети настолько большой, что тренировка падает из-за нехватки памяти. В ущерб времени обучения можно воспользоваться чекпоинтом градиентов — это когда мы в каждом слое на входе сохраняем входное значение, а во время обратного распространения ошибки будет вычислять значение на выходе слоя заново. Говорят, что можно неплохо так экономить память. Чекайте этот гайд.
🤯 Сейчас популярен подход к моделькам глубокого обучения: модель — это код. Это значит, что мы берем результат обучения и представляем его в виде оптимизированного кода. И тут я наткнулся на TVM. Здесь ребята делают не просто код, а промежуточное представление, которое потом можно использовать на куче различных устройств бесплатно без смс и регистрации. Вот видосик про то, как можно это попробовать использовать для своих моделей.
Если вы занимаетесь подобными темами, буду рад ссылочкам на подобные материалы!
#разработка
Вот что было просмотрено быстро глазами и добавлено в заметки на подробное изучение.
⚡️ Как добиться сходимости быстрее. Безусловно, одна из самых важных проблем — нейронные сети обучаются долго (долго сходятся). Есть множество хаков. Одни из них здесь: Тык1, Тык2.
👀 Чтобы ускориться, можно использовать quantization. Это когда мы жертвуем точностью вычисление во благо времени исполнения (не всегда качество страдает). Не всегда такие операции применимы, но в целом если задумались о таком методе — вот неплохой гайд.
👻 Бывает, что вычислительный граф во время обучения нейронной сети настолько большой, что тренировка падает из-за нехватки памяти. В ущерб времени обучения можно воспользоваться чекпоинтом градиентов — это когда мы в каждом слое на входе сохраняем входное значение, а во время обратного распространения ошибки будет вычислять значение на выходе слоя заново. Говорят, что можно неплохо так экономить память. Чекайте этот гайд.
🤯 Сейчас популярен подход к моделькам глубокого обучения: модель — это код. Это значит, что мы берем результат обучения и представляем его в виде оптимизированного кода. И тут я наткнулся на TVM. Здесь ребята делают не просто код, а промежуточное представление, которое потом можно использовать на куче различных устройств бесплатно без смс и регистрации. Вот видосик про то, как можно это попробовать использовать для своих моделей.
Если вы занимаетесь подобными темами, буду рад ссылочкам на подобные материалы!
#разработка
👍3
Когда я был просто разработчиком — было все просто, берешь задачу и делаешь. Сейчас же у меня добавились управленческие задачи и само понятие "задача" как-то размылось. Да что уж там говорить, очень много задач назначаются мне самим же собой.
Сразу отвечу на вопрос "А как же задачи руководства?" Естественно, они есть. Их немало, но зачастую это высокоуровневые задачи, которые лучше бы еще декомпозировать. Редко бывает задача: "Антоха, там библиотечку прикольную нашли, надо бы её прикрутить по этой инструкции". Обычно это: "Антоха, бизнес хочет вот это — реши плз". И ты идешь и начинаешь решать: а как декомпозировать? А кто этим будет заниматься? А что для этого надо? А чего это будет нам стоить (в плане человеческих ресурсов). 🤯
И вот с такими задачами я начал за собой замечать, что очень сложно сделать первый шаг. Я думаю, что задача очень большая, так не хочется за неё браться, ведь рядом еще 100500 задач, которые нужно решить (на самом деле эти 100500 задач похожего плана). Я даже стал практиковать написание первого действия к подобным задачам, чтобы была бОльшая мотивация их делать. Что самое интересное, как только я начинаю решать задачу — это оказывается очень интересно.
Но на помощь ко мне пришел спорт и недавние тренировки в зале 💪. Тренер мне начал давать усилинные тренировки с бОльшими весами. Естественно, после каждого подхода я очень сильно не хотел делать следующий. Организм сопротивлялся, в голове куча разных мыслей. Но на то мне и тренер, чтобы он заставил сделать подход. И как только я начинал делать — все сразу становилось хорошо: ничего не болело и была куча сил для покорения очередного мини-олимпа.
Теперь в своих делах я также практикую "тренера". Я использую различные биохаки, чтобы заставить себя сесть за задачу. А дальше всё как по маслу. Одни из них: ставлю жесткий дедлайн на задачу сегодня (мне очень грустно, если я просрочил дедлайн); надумываю, что от этой задачи зависит очень многое (морально мне это дается легко, но вам не советую).
А какие вы используете трюки, чтобы заставить себя сделать первый шаг? 🤔
#управление
Сразу отвечу на вопрос "А как же задачи руководства?" Естественно, они есть. Их немало, но зачастую это высокоуровневые задачи, которые лучше бы еще декомпозировать. Редко бывает задача: "Антоха, там библиотечку прикольную нашли, надо бы её прикрутить по этой инструкции". Обычно это: "Антоха, бизнес хочет вот это — реши плз". И ты идешь и начинаешь решать: а как декомпозировать? А кто этим будет заниматься? А что для этого надо? А чего это будет нам стоить (в плане человеческих ресурсов). 🤯
И вот с такими задачами я начал за собой замечать, что очень сложно сделать первый шаг. Я думаю, что задача очень большая, так не хочется за неё браться, ведь рядом еще 100500 задач, которые нужно решить (на самом деле эти 100500 задач похожего плана). Я даже стал практиковать написание первого действия к подобным задачам, чтобы была бОльшая мотивация их делать. Что самое интересное, как только я начинаю решать задачу — это оказывается очень интересно.
Но на помощь ко мне пришел спорт и недавние тренировки в зале 💪. Тренер мне начал давать усилинные тренировки с бОльшими весами. Естественно, после каждого подхода я очень сильно не хотел делать следующий. Организм сопротивлялся, в голове куча разных мыслей. Но на то мне и тренер, чтобы он заставил сделать подход. И как только я начинал делать — все сразу становилось хорошо: ничего не болело и была куча сил для покорения очередного мини-олимпа.
Теперь в своих делах я также практикую "тренера". Я использую различные биохаки, чтобы заставить себя сесть за задачу. А дальше всё как по маслу. Одни из них: ставлю жесткий дедлайн на задачу сегодня (мне очень грустно, если я просрочил дедлайн); надумываю, что от этой задачи зависит очень многое (морально мне это дается легко, но вам не советую).
А какие вы используете трюки, чтобы заставить себя сделать первый шаг? 🤔
#управление
👍3🤯1
ELF файлы
Мало кто знает, но в Unix-подобных системах существуют ELF (Executable and Linkable Format) файлы. Удивительно, но эти малыши 👶 позволяют вашим программам работать, в вам зарабатывать деньги 🤑.
В целом, не вдаваясь в детали, ELF предоставляет стандарт, по которому формируется бинари: исполняемые файлы или бибилиотки (не с книгами, с кодом). ELF содержит информацию о зависимостях, о самом коде (секция
Меньше слов, больше дела. Пусть дан простенький код на C++:
Соберем его с помощью компилятора gcc следующей командой:
Можете даже запустить его командой:
Большинство из нас в универах учили, что вот компилятор берет такой молодец, компилирует и превращает ваш код в машинный код 🪄. Отчасти это правда, отчасти нет. Дело в том, что
А теперь магия 🧙. Найдем переменные. Для начала найдем константную переменную
Круто же 😏? Мы только что нашли константую строку в приложении, которое нам говорили, что читать невозможно. А вот оказывается можно. Давайте пойдем дальше, что там насчет переменной
В этот раз наше значение зашито в чиселке
Знать ELF формат хорошо. Умные люди могут даже им манипулировать и загружать быстрее приложеньки. Можно находить различные зависимости и примерно понимать, почему бинарь у вас не работает. Но широким применением этот формат пользуется в информационной безопасности: позволяет находить и закрывать дыры в безопасности приложения (чтобы сливов с icloud было меньше). 😍
Пишите комментарии, если чего не понятно!
#разработка
Мало кто знает, но в Unix-подобных системах существуют ELF (Executable and Linkable Format) файлы. Удивительно, но эти малыши 👶 позволяют вашим программам работать, в вам зарабатывать деньги 🤑.
В целом, не вдаваясь в детали, ELF предоставляет стандарт, по которому формируется бинари: исполняемые файлы или бибилиотки (не с книгами, с кодом). ELF содержит информацию о зависимостях, о самом коде (секция
.text), глобальные таблицы и переменные (секция .data), константы (секция .rodata — read-only data) и многое другое. Также формат позволяет быстро узнать, под какую архитектуру процессора был сделан бинарь, владеет информацией о том, какие манипуляции OS нужно сделать 🤯, чтобы загрузить этот бинарь в оперативную память. Меньше слов, больше дела. Пусть дан простенький код на C++:
// simple.cppint x = 100500;
int main() {
const char* str = "lol kek cheburek";
return 0;
}Соберем его с помощью компилятора gcc следующей командой:
gcc simple.cpp -o simple. Ура, мы собрали бесполезную программу 🥲, которая хранит глобальную изменяемую переменную (x), а также константную строку (str). Можете даже запустить его командой:
./simple — но ничего не будет выведено, мы же ничего не делаем. Большинство из нас в универах учили, что вот компилятор берет такой молодец, компилирует и превращает ваш код в машинный код 🪄. Отчасти это правда, отчасти нет. Дело в том, что
simple — это исполняемый файл в Linux, а значит формата ELF в большинстве случаев. А теперь магия 🧙. Найдем переменные. Для начала найдем константную переменную
str. Комманда objdump -s -j .rodata simple выдаст следующий результат: Contents of section .rodata:
2000 01000200 6c6f6c20 6b656b20 63686562 ....lol kek cheb
2010 7572656b 00 urek. Круто же 😏? Мы только что нашли константую строку в приложении, которое нам говорили, что читать невозможно. А вот оказывается можно. Давайте пойдем дальше, что там насчет переменной
x? Ок, пишем комманду: objdump -s -j .data simple. Получаем примерно следующее: Contents of section .data:
4000 00000000 00000000 08400000 00000000 .........@......
4010 94880100 .... В этот раз наше значение зашито в чиселке
94880100. Не верите? Переходите сюда и проверьте секцию UINT32 - Little Endian. И найдете там чиселку. Строчка выше содержит служебные данные. Но классно, что мы смогли найти переменную ☺️. Но если у вас их будет много, так просто не получится это сделать. Но это уже не предмет текущего поста. Знать ELF формат хорошо. Умные люди могут даже им манипулировать и загружать быстрее приложеньки. Можно находить различные зависимости и примерно понимать, почему бинарь у вас не работает. Но широким применением этот формат пользуется в информационной безопасности: позволяет находить и закрывать дыры в безопасности приложения (чтобы сливов с icloud было меньше). 😍
Пишите комментарии, если чего не понятно!
#разработка
👍3🔥2🤡1
Хороший ли у меня руководитель? 🤔
Зачастую на работе у каждого из нас есть руководитель (начальник).
Здесь и далее я предпочитаю избегать слово начальник. Как по мне оно носит иерархический характер и несёт контекст подчинения. В конце-концов, на работе у каждого своя роль и свой набор обязанностей, поэтому начальник — звучит вычурно и лично мне напоминает армейский строй.
Для каждого, конечно, свои критерии того, каким должен быть их "хороший" руководитель по отношению к ним. Но здесь я выписал то, каким хочу выглядеть я в глазах ребят из моих команд, каким хочу чтобы выглядел мой руководитель.
😇 Руководитель — это наставник
По мне, руководитель должен быть способен отвечать на любые мои вопросы. А если он не может, то зачастую может показать направление, куда двигаться, чтобы получить ответ. И это касается не только рабочих, но и личных вопросов. Он знает, как мне можно помочь развиться, и мы вместе двигаемся в этом направлении.
🥷 Руководитель — мой мотиватор
Я смотрю на него и понимаю — чорт, да он крут. И не обязательно, что я хочу быть как он (что бессмысленно), но его личные качества побуждают меня к работе. У меня появляется желание работать именно с ним, он дает мне отличное представление того, зачем мы сейчас делаем то, чего делаем. А если я стал в чем-то сомневаться, я всегда знаю, что мы можем с ним это обсудить и найти путь для решения этой проблемы.
👀 Руководитель — мой ментор
Если я не знаю, как решить задачу — мой руководитель обсудит со мной пути решения задачи. Но если он знает ответ, чаще всего он до последнего не будет его рассказывать, потому что ему важнее развитие меня, нежели выполнение задачи раньше срока. Он знает, что сегодня он помогает мне, а завтра я помогаю своим коллегам и т.д.
🦸 Руководитель — мой супергерой
Он защитит меня от любых врагов. Он знает, что мне работается лучше, если я не беспокоюсь, если меня не дергают, если меня никто не достает в рабочее время из других отделов. Он защищает рубежи нашей команды от любой нечисти снаружи.
🤵 Руководитель — мой авторитет
Несмотря на то, что иногда его действия могут быть для меня странными и все такое, руководитель для меня авторитет. Он помогает двигаться нам по проекту, он всячески старается контроллировать и сдвигать сроки, в случае неудач. И за это все я готов его уважать и принимать во внимание его пожелания и требования.
Безусловно, этот список можно продолжать дальше. Но здесь наверное основное на текущем этапе моего развития. Интересное наблюдение, что зачастую такими являются наши родители (ну по крайней мере мои).
А каков ваш хороший руководитель? 😏
#управление
Зачастую на работе у каждого из нас есть руководитель (начальник).
Здесь и далее я предпочитаю избегать слово начальник. Как по мне оно носит иерархический характер и несёт контекст подчинения. В конце-концов, на работе у каждого своя роль и свой набор обязанностей, поэтому начальник — звучит вычурно и лично мне напоминает армейский строй.
Для каждого, конечно, свои критерии того, каким должен быть их "хороший" руководитель по отношению к ним. Но здесь я выписал то, каким хочу выглядеть я в глазах ребят из моих команд, каким хочу чтобы выглядел мой руководитель.
😇 Руководитель — это наставник
По мне, руководитель должен быть способен отвечать на любые мои вопросы. А если он не может, то зачастую может показать направление, куда двигаться, чтобы получить ответ. И это касается не только рабочих, но и личных вопросов. Он знает, как мне можно помочь развиться, и мы вместе двигаемся в этом направлении.
🥷 Руководитель — мой мотиватор
Я смотрю на него и понимаю — чорт, да он крут. И не обязательно, что я хочу быть как он (что бессмысленно), но его личные качества побуждают меня к работе. У меня появляется желание работать именно с ним, он дает мне отличное представление того, зачем мы сейчас делаем то, чего делаем. А если я стал в чем-то сомневаться, я всегда знаю, что мы можем с ним это обсудить и найти путь для решения этой проблемы.
👀 Руководитель — мой ментор
Если я не знаю, как решить задачу — мой руководитель обсудит со мной пути решения задачи. Но если он знает ответ, чаще всего он до последнего не будет его рассказывать, потому что ему важнее развитие меня, нежели выполнение задачи раньше срока. Он знает, что сегодня он помогает мне, а завтра я помогаю своим коллегам и т.д.
🦸 Руководитель — мой супергерой
Он защитит меня от любых врагов. Он знает, что мне работается лучше, если я не беспокоюсь, если меня не дергают, если меня никто не достает в рабочее время из других отделов. Он защищает рубежи нашей команды от любой нечисти снаружи.
🤵 Руководитель — мой авторитет
Несмотря на то, что иногда его действия могут быть для меня странными и все такое, руководитель для меня авторитет. Он помогает двигаться нам по проекту, он всячески старается контроллировать и сдвигать сроки, в случае неудач. И за это все я готов его уважать и принимать во внимание его пожелания и требования.
Безусловно, этот список можно продолжать дальше. Но здесь наверное основное на текущем этапе моего развития. Интересное наблюдение, что зачастую такими являются наши родители (ну по крайней мере мои).
А каков ваш хороший руководитель? 😏
#управление
🤡1
Shell vs Exec режимы в Dockerfile 🐬
Сложненькая неделька выдалась 🙈. Мало спал и писал статью на конференцию как сопровождение к магистерской диссертации. Надеюсь, вышло успешно. Результаты будут где-то 25 марта.
Собственно я немного отдохнул и готов рассказать интересную особенность в Dockerfile. Если вы не знаете, что такое докер или докер-файл, отправляю вас к этой статье, в которой вполне хорошо описаны основные принципы работы технологии.🙂
Итак, когда мы собираем докеробраз, мы обязательно должны указать команду, с которой будет запускаться базирующийся на основе образа контейнер. Для этого существует два пути:
Для каждой из этих инструкций существует два варианта записи команды:
или
И да, они отличаются 😅. Видите ли что, контейнеризация подразумевает запуск приложения в определенном окружении. И в случае
Плох ли какой-то вариант🤔? Да в целом нет. Но все зависит от задачи. Если вам нужны какие-то инструменты командного интерпретатора (типа переменной
Подробнее про все это можно почитать в статье. Или в документации.
P.S. Буду как блоггер выпрашивать с вас реакции 🙂 Подписывайтесь, ставьте реакции, пишите комментарии!
#разработка
Сложненькая неделька выдалась 🙈. Мало спал и писал статью на конференцию как сопровождение к магистерской диссертации. Надеюсь, вышло успешно. Результаты будут где-то 25 марта.
Собственно я немного отдохнул и готов рассказать интересную особенность в Dockerfile. Если вы не знаете, что такое докер или докер-файл, отправляю вас к этой статье, в которой вполне хорошо описаны основные принципы работы технологии.🙂
Итак, когда мы собираем докеробраз, мы обязательно должны указать команду, с которой будет запускаться базирующийся на основе образа контейнер. Для этого существует два пути:
CMD и ENTRYPOINT.Для каждой из этих инструкций существует два варианта записи команды:
ENTRYPOINT "/bin/bash" # shell resumeили
ENTRYPOINT ["/bin/bash"] # exec resumeИ да, они отличаются 😅. Видите ли что, контейнеризация подразумевает запуск приложения в определенном окружении. И в случае
exec режима, так и получается, что если мы запустим контейнер, то самым первым процессом будет наше приложение. А в случае shell, первым процессом будет коммандная оболочка (обычно это /bin/sh). А это значит + один лишний процесс во время исполнения. А также посылаемые сигналы от OS будут идти не к вашему приложению, а к оболочке, что может вызывать боль иногда. Плох ли какой-то вариант🤔? Да в целом нет. Но все зависит от задачи. Если вам нужны какие-то инструменты командного интерпретатора (типа переменной
$PATH или автоподстановка выражений заместо *.ext), то вам нужен режим оболочки. Во всех остальных случаях рекомендуется использовать exec режим (только в этом случае все пути до файлов нужно указывать полностью). Подробнее про все это можно почитать в статье. Или в документации.
P.S. Буду как блоггер выпрашивать с вас реакции 🙂 Подписывайтесь, ставьте реакции, пишите комментарии!
#разработка
👍4🔥1🤡1
Оптимизация математики в GCC
Помните, как в школе нас просили упростить математические выражения? Что-то типа
Так и зачем? Были бы программки быстрее, VPN работал шустрее (но это не точно) 😅. Допустим есть следующая функция:
Эта функция возводит число в квадрат и потом извлекает корень. Ну прям как в школьном примере выше 🤓.
Иногда такое (бессмысленное) встречается, особенно в исследовательском коде 🧐. Зачем — не спрашивайте, я даже не знаю. Самое интересно, что если скоратить эту функцию, как мы делали в школе — то решение будет работать уже не совсем точно. Это связано с тем, что часто исследователи закладываются на вычислительные ошибки, связаные с представлением чисел с плавающей точкой (то, что обычно мы называем десятичная дробь).
Так вот, в копиляторе GCC существует флаг
Грамотная оптимизация всегда позволяет сделать приложение быстрее. Например, если вы воспользуетесь флагом
Напоследок порекомендую интересную статью про то, как влияют различные флаги оптимизации математики. Ну и конечно, читайте документацию, всегда полезно.
#разработка
Помните, как в школе нас просили упростить математические выражения? Что-то типа
корень из x * x = x. Так вот, компиляторы умеют также. Только по умолчанию им это делать запрещено 🤷Так и зачем? Были бы программки быстрее, VPN работал шустрее (но это не точно) 😅. Допустим есть следующая функция:
#include <cmath>
float root_of_square(float value) {
return std::sqrt(value * value);
}
Эта функция возводит число в квадрат и потом извлекает корень. Ну прям как в школьном примере выше 🤓.
Иногда такое (бессмысленное) встречается, особенно в исследовательском коде 🧐. Зачем — не спрашивайте, я даже не знаю. Самое интересно, что если скоратить эту функцию, как мы делали в школе — то решение будет работать уже не совсем точно. Это связано с тем, что часто исследователи закладываются на вычислительные ошибки, связаные с представлением чисел с плавающей точкой (то, что обычно мы называем десятичная дробь).
Так вот, в копиляторе GCC существует флаг
-ffast-math, который включает целый класс оптимизаций математических операций во время сборки приложения. Про этот флаг обычно говорят: если не знаешь, лучше не трогай. И это действительно так, если его применить, то даже без вмешательства нашей школьной оптимизации, компилятор сам поймет, что тут можно оптимизировать и сделает это. А потом вы будете искать баги днями и ночами, потому что такое найти — ну оооочень сложно🤪. Грамотная оптимизация всегда позволяет сделать приложение быстрее. Например, если вы воспользуетесь флагом
-fassociative-math, который входит в состав -ffast-math, то это позволит задействовать ассоциативные правила из математики. Это также повлияет на циклы, ведь возможна ситуация, когда вычисления можно векторизовать (выполнить одновременно). Напоследок порекомендую интересную статью про то, как влияют различные флаги оптимизации математики. Ну и конечно, читайте документацию, всегда полезно.
#разработка
👍2🔥2🤡1
Abseil
👨💻Сегодня мне хочется написать об очень крутом сборнике библиотек для С++ — Abseil. Чтобы не быть голословным, я просто оставлю здесь то, что написано у них на сайте о себе:
Abseil encompasses the most basic building blocks of Google’s codebase: code that is production-tested and will be fully maintained for years to come.
С чего всё началось?
Как я понял, ребятки в Google очень любят писать хороший, быстрый, чистый (и всякие другие эпитеты) код 🤫. В куче своих проектов, они использовали одни и те же сущности, который можно было бы выделить в отдельное место. Общие части однажды вынесли и появился Abseil. 👶
Ну например, в С++11 не было метода std::make_unique. В библиотеке memory, которая находится в составе Abseil, он реализован. Или, например, понадобился вам std::variant в С++11 — пожалуйста, берите из библиотеки types.
Почему Abseil, а не что-то другое 🤔?
Каждую сущность выше можно было бы реализовать самим, найти отдельные имплементации. Есть несколько но:
1. Код Abseil протестирован — это очень важно, когда вы пишите код для реальных систем;
2. Код Abseil зарекомендовал себя временем и именитыми пользователями — не буду возвышать здесь Google, но раз они у себя его используют, это повод задуматься (они же могут 100500 раз написать подобное сами);
3. Apache 2 лицензия — можно использовать как в open-source, так и в коммерческих проектах бесплатно💸!
Почему я вообще о ней заговорил?
Эта библиотека мне уже парочку раз спасла жизнь ☺️. Особенно когда мы написали очень много кода на С++17, а тут по стечению обстоятельств оказалось, что нужно использовать С++11 🤷. С точностью до некоторых моментов, Abseil позволяет это сделать очень просто. А если вы использовали этот сборник с самого начала проекта — переход между стандартами языка осуществляется простой сменой флага в системе сборки.
Также мне приятно читать их код. Не знаю, почему так происходит, но для меня он опрятен и вызывает мурашки. При должном внимании, можно понять, что происходит — не всегда такое возможно.
В общем-то, если когда-то будете писать на С++, подумайте, возможно использование Abseil может помочь вам решить незакрытые вопросики.
#разработка
👨💻Сегодня мне хочется написать об очень крутом сборнике библиотек для С++ — Abseil. Чтобы не быть голословным, я просто оставлю здесь то, что написано у них на сайте о себе:
Abseil encompasses the most basic building blocks of Google’s codebase: code that is production-tested and will be fully maintained for years to come.
С чего всё началось?
Как я понял, ребятки в Google очень любят писать хороший, быстрый, чистый (и всякие другие эпитеты) код 🤫. В куче своих проектов, они использовали одни и те же сущности, который можно было бы выделить в отдельное место. Общие части однажды вынесли и появился Abseil. 👶
Ну например, в С++11 не было метода std::make_unique. В библиотеке memory, которая находится в составе Abseil, он реализован. Или, например, понадобился вам std::variant в С++11 — пожалуйста, берите из библиотеки types.
Почему Abseil, а не что-то другое 🤔?
Каждую сущность выше можно было бы реализовать самим, найти отдельные имплементации. Есть несколько но:
1. Код Abseil протестирован — это очень важно, когда вы пишите код для реальных систем;
2. Код Abseil зарекомендовал себя временем и именитыми пользователями — не буду возвышать здесь Google, но раз они у себя его используют, это повод задуматься (они же могут 100500 раз написать подобное сами);
3. Apache 2 лицензия — можно использовать как в open-source, так и в коммерческих проектах бесплатно💸!
Почему я вообще о ней заговорил?
Эта библиотека мне уже парочку раз спасла жизнь ☺️. Особенно когда мы написали очень много кода на С++17, а тут по стечению обстоятельств оказалось, что нужно использовать С++11 🤷. С точностью до некоторых моментов, Abseil позволяет это сделать очень просто. А если вы использовали этот сборник с самого начала проекта — переход между стандартами языка осуществляется простой сменой флага в системе сборки.
Также мне приятно читать их код. Не знаю, почему так происходит, но для меня он опрятен и вызывает мурашки. При должном внимании, можно понять, что происходит — не всегда такое возможно.
В общем-то, если когда-то будете писать на С++, подумайте, возможно использование Abseil может помочь вам решить незакрытые вопросики.
#разработка
🔥1🤡1
AddressSanitizer
В
Представьте, вы приехали домой. Вам сварили борщик, вкусный такой, нажористый, домашний 🍛. Подали кусочек ржаного хлебшука, натертого с чесночком, да и сальце тоже не забыли 🍞. Будем считать это аналогией инициализации ресурсов в программе.
Вы кушаете борщик, вспоминаете детство, закусываете кусочком хлеба. OMG, думаете вы, как вкусно 😍. Но борщик постепенно заканчивается, но вам всё равно. Вы не замечаете, как съедаете борщик 😅. Всё, мы тут воспользовались ресурсами и уничтожили их в программе.
А теперь самое интересное: вы тянетесь ложкой в тарелочку с борщиком, всё в мыслях, кладете эту ложку в рот и тут уже понимаете, что ложка-то пустая, борщ съеден уже был 🤨. Вот тут мы в разработке сталкиваемся с обращением к ресурсу, который уже уничтожили.
В реальности, никаких проблем нет. Ну пустая ложка и пустая (хотя обидно всё же). А в приложении обычно ложек пустых не бывает (допустим, тарелка заполнилась землей автоматически), а значит мы "скушаем" чего-то не то, от этого будут проблемы 🤯.
И в лучшем случае, хорошо, если мы обращаемся к ресурсу на чтение. А если запись? А если ресурсы системные? В общем — это больно, тяжело ловить при отладке 😢.
Вообще в компиляторах есть несколько инструментов типа
В своих проектах я предпочитаю использовать все инструменты, если это необходимо и если это возможно 🤗. Это помогает отлавливать совсем неочевидные ошибки и много раз спасало от возможных проблем 🥲. Хотя, конечно, это не панацея — у него есть и свои баги, свои ложные срабатывания/не срабатывания.
Также
И еще пару слов про то, почему не всегда возможно использовать инструмент. Некоторые сторонние зависимости имеют баги🥷, если их очень много, даже если ваше приложение написано идеально, санитайзер будет ругаться 😡. И тут нужно быть просто осторожным и искать проблему там, где она есть, а не где думается.
Напоследок два доклада про санитайзер на русском: тык, тык. На английском: тык. Презентация с одного из докладов: тык.
#разработка
В
С++ компиляторах (по крайней мере, в gcc/clang), есть такая штука, как AddressSanitizer. Она помогает находить ошибки адрессации в коде. Объясню на простеньком примере 👶. Представьте, вы приехали домой. Вам сварили борщик, вкусный такой, нажористый, домашний 🍛. Подали кусочек ржаного хлебшука, натертого с чесночком, да и сальце тоже не забыли 🍞. Будем считать это аналогией инициализации ресурсов в программе.
Вы кушаете борщик, вспоминаете детство, закусываете кусочком хлеба. OMG, думаете вы, как вкусно 😍. Но борщик постепенно заканчивается, но вам всё равно. Вы не замечаете, как съедаете борщик 😅. Всё, мы тут воспользовались ресурсами и уничтожили их в программе.
А теперь самое интересное: вы тянетесь ложкой в тарелочку с борщиком, всё в мыслях, кладете эту ложку в рот и тут уже понимаете, что ложка-то пустая, борщ съеден уже был 🤨. Вот тут мы в разработке сталкиваемся с обращением к ресурсу, который уже уничтожили.
В реальности, никаких проблем нет. Ну пустая ложка и пустая (хотя обидно всё же). А в приложении обычно ложек пустых не бывает (допустим, тарелка заполнилась землей автоматически), а значит мы "скушаем" чего-то не то, от этого будут проблемы 🤯.
И в лучшем случае, хорошо, если мы обращаемся к ресурсу на чтение. А если запись? А если ресурсы системные? В общем — это больно, тяжело ловить при отладке 😢.
Вообще в компиляторах есть несколько инструментов типа
*Sanitizer: ThreadSanitizer — помогает находить ошибки в многопоточном приложении, когда два или более потоков пытаются менять одну и ту же область памяти;LeakSanitizer — обычно включается вместе с AddressSanitizer и нужен для поиска утечек памяти;UndefinedBehaviorSanitizer — инструмент для поиска undefined behavior аномалий.В своих проектах я предпочитаю использовать все инструменты, если это необходимо и если это возможно 🤗. Это помогает отлавливать совсем неочевидные ошибки и много раз спасало от возможных проблем 🥲. Хотя, конечно, это не панацея — у него есть и свои баги, свои ложные срабатывания/не срабатывания.
Также
AddressSanitizer выделяется на фоне всех остальных похожих инструментов своим быстродействием ⚡️. Разработчики запарились и придумали просто гениальную стратегию отслеживания работы с памятью. Советую ознакомиться с принципом работы инструмента. И еще пару слов про то, почему не всегда возможно использовать инструмент. Некоторые сторонние зависимости имеют баги🥷, если их очень много, даже если ваше приложение написано идеально, санитайзер будет ругаться 😡. И тут нужно быть просто осторожным и искать проблему там, где она есть, а не где думается.
Напоследок два доклада про санитайзер на русском: тык, тык. На английском: тык. Презентация с одного из докладов: тык.
#разработка
🔥5❤1😱1🤡1
CalDigit TS4
Я тот еще фанат техники🥷. Совсем недавно я стал задумываться, как бы обустроить своё рабочее место.
Я думаю над тем, чтобы купить ортопедическое кресло Herman Miller (правда, сейчас оно стоит просто нереальных денег) и стол с механизмом автоподъема, например от этих ребят.💸 Но это всё базовые вещи (в плане стол + кресло), без которых комфортабельное рабочее место невозможно.
Те, кто организовывал (или пытался) своё рабочее пространство, знают, что одна из больших болей — это провода😢. Их может быть 100500, а хочется получить немного эстетического удовольствия от рабочего места.☺️
Большинство проводки можно спрятать под стол.😉 Но очень много девайсов нужно подключать к макбуку — у которого в лучшем случае портов 4, в среднем — два. В моем случае это целый набор: внешний SSD, монитор, мышка, зарядка, иногда зарядка для часов, иногда еще что-то🤯. В итоге мой макбук стоит как чудище с руками-проводами🧟. А еще это очень некомфортно каждый раз отсоединять/присоединять, когда нужно взять ноутбук с собой.😓
Я стал гуглить, как вообще люди обходятся в таком случае, кейс же частый. Оказывается, все уже придумали. Я бы назвал эту концепцию — магия одного провода.💫
Суть в том, что вы соединяете макбук (или ваш ноутбук) с док станцией по кабелю. Пока ничего нового. Но давайте взглянем на вот эту штучку — CalDigit TS4.
Серьезно? 18 портов? Одновременная зарядка с передачей данных? 2.5 Гбит порт интернета? 10 Гб/с передача данных по USB-C? Подключение к монитору? И это всё по одному кабелю? Что за магия?🤷
Оказывается, всё очень просто. Ребятки из Intel вместе с Apple разработали стандарт Thunderbolt. И уже давно как макбуки и продвинутые ноуты содержат разъёмы с этой технологией. 🤨
Если честно, я всегда думал, что это какая-то маркетинговая фишка Apple, мол не USB-C, а Thunderbolt (они же так любят делать). Оказывается это очень мощная штука. За счет конструктивных особенностей данный разъем позволяет поддерживать огромное число устройств, а также передавать данные с бешенной скоростью. 🤓
Но Thunderbolt — это не только разъем, но и провод. И тут вообще всё очень сложно. Чтобы поддерживать заявленную пропускную способность, медный вариант кабеля пока может достигать только 3м в длину. Где-то пишут, что есть оптоволоконные Thunderbolt кабели и они могут достагать 30м в длину.🙈
И что нам даёт знание о длине? Только лишь то, что эти кабели из-за своих конструктивных особенностей стоят бешенных денег. Например, у того же CalDigit кабель Thunderbolt 4 на 2м стоит $75. Неплохо так. 💸
К чему этот текст про Thunderbolt? Когда вы видите кабель от Apple, который стоит в 20 раз дороже китайского, то это не только за бренд. Огромные силы вложены даже в простой переходник, чтобы тот выдавал вам максимум от используемых девайсов. Так что покупайте оригиналы, не путайте провода для своих девайсов.
Немного интересной информации про Thunderbolt вы можете прочитать здесь. Кстати говоря, описывают в чем разница между 3 и 4 стандартами.
А CalDigit TS4 я планирую себе купить. Правда пока не знаю, как это сделать из РФ. Может быть кто-то может помочь, кто сейчас зарубежом?🙏
#разное
Я тот еще фанат техники🥷. Совсем недавно я стал задумываться, как бы обустроить своё рабочее место.
Я думаю над тем, чтобы купить ортопедическое кресло Herman Miller (правда, сейчас оно стоит просто нереальных денег) и стол с механизмом автоподъема, например от этих ребят.💸 Но это всё базовые вещи (в плане стол + кресло), без которых комфортабельное рабочее место невозможно.
Те, кто организовывал (или пытался) своё рабочее пространство, знают, что одна из больших болей — это провода😢. Их может быть 100500, а хочется получить немного эстетического удовольствия от рабочего места.☺️
Большинство проводки можно спрятать под стол.😉 Но очень много девайсов нужно подключать к макбуку — у которого в лучшем случае портов 4, в среднем — два. В моем случае это целый набор: внешний SSD, монитор, мышка, зарядка, иногда зарядка для часов, иногда еще что-то🤯. В итоге мой макбук стоит как чудище с руками-проводами🧟. А еще это очень некомфортно каждый раз отсоединять/присоединять, когда нужно взять ноутбук с собой.😓
Я стал гуглить, как вообще люди обходятся в таком случае, кейс же частый. Оказывается, все уже придумали. Я бы назвал эту концепцию — магия одного провода.💫
Суть в том, что вы соединяете макбук (или ваш ноутбук) с док станцией по кабелю. Пока ничего нового. Но давайте взглянем на вот эту штучку — CalDigit TS4.
Серьезно? 18 портов? Одновременная зарядка с передачей данных? 2.5 Гбит порт интернета? 10 Гб/с передача данных по USB-C? Подключение к монитору? И это всё по одному кабелю? Что за магия?🤷
Оказывается, всё очень просто. Ребятки из Intel вместе с Apple разработали стандарт Thunderbolt. И уже давно как макбуки и продвинутые ноуты содержат разъёмы с этой технологией. 🤨
Если честно, я всегда думал, что это какая-то маркетинговая фишка Apple, мол не USB-C, а Thunderbolt (они же так любят делать). Оказывается это очень мощная штука. За счет конструктивных особенностей данный разъем позволяет поддерживать огромное число устройств, а также передавать данные с бешенной скоростью. 🤓
Но Thunderbolt — это не только разъем, но и провод. И тут вообще всё очень сложно. Чтобы поддерживать заявленную пропускную способность, медный вариант кабеля пока может достигать только 3м в длину. Где-то пишут, что есть оптоволоконные Thunderbolt кабели и они могут достагать 30м в длину.🙈
И что нам даёт знание о длине? Только лишь то, что эти кабели из-за своих конструктивных особенностей стоят бешенных денег. Например, у того же CalDigit кабель Thunderbolt 4 на 2м стоит $75. Неплохо так. 💸
К чему этот текст про Thunderbolt? Когда вы видите кабель от Apple, который стоит в 20 раз дороже китайского, то это не только за бренд. Огромные силы вложены даже в простой переходник, чтобы тот выдавал вам максимум от используемых девайсов. Так что покупайте оригиналы, не путайте провода для своих девайсов.
Немного интересной информации про Thunderbolt вы можете прочитать здесь. Кстати говоря, описывают в чем разница между 3 и 4 стандартами.
А CalDigit TS4 я планирую себе купить. Правда пока не знаю, как это сделать из РФ. Может быть кто-то может помочь, кто сейчас зарубежом?🙏
#разное
🤯2👍1🤔1🤡1
Конференция 🤓
Ух! Как давно я не писал! Задались плотные деньки!
Подготовка диплома, новые проекты на работе 🙂
По правилам магистратуры, студент должен написать статью или выступить с докладом на конференции. Тема работы должна каким-то образом соприкасаться с выпускной квалификационной работой. 🤓
Как и бывает в любом стартапе — мы просрочили все дедлайны. И успевали подать только на одну конференцию — FRUCT. В целом забавная тусовка, но рейтинг у неё околонулевой. 😢
Ну делать было нечего — пишем. Это была моя первая собственная статья, которую я написал сам. Так еще и на английском языке. В начале работы я вообще не верил, что смогу — но получилось. Это был сложный месяц февраль. Мне кажется, что я со своим научником сделали какую-то нереальную работу.🥷
Во время выступления на конференции в моей группе были ребята в основном русские, но все говорили на английском. Эдакий "Science English Club". 🤫
Мне было интересно поучаствовать во всём этом. Но также я понял, что написание статей — это не моё. Слишком много формальностей, слишком многим нужно доказать (если у тебя нет авторитета в научном мире). И это даже для околонулевой конференции. Я лучше буду писать код, работать с людьми, делать "промышленное" исследование, а науку оставлю ребятам, которые в ней понимают и которым она доставляет удовольствие. 😇
Ссылочка на мою работу.
Ух! Как давно я не писал! Задались плотные деньки!
Подготовка диплома, новые проекты на работе 🙂
По правилам магистратуры, студент должен написать статью или выступить с докладом на конференции. Тема работы должна каким-то образом соприкасаться с выпускной квалификационной работой. 🤓
Как и бывает в любом стартапе — мы просрочили все дедлайны. И успевали подать только на одну конференцию — FRUCT. В целом забавная тусовка, но рейтинг у неё околонулевой. 😢
Ну делать было нечего — пишем. Это была моя первая собственная статья, которую я написал сам. Так еще и на английском языке. В начале работы я вообще не верил, что смогу — но получилось. Это был сложный месяц февраль. Мне кажется, что я со своим научником сделали какую-то нереальную работу.🥷
Во время выступления на конференции в моей группе были ребята в основном русские, но все говорили на английском. Эдакий "Science English Club". 🤫
Мне было интересно поучаствовать во всём этом. Но также я понял, что написание статей — это не моё. Слишком много формальностей, слишком многим нужно доказать (если у тебя нет авторитета в научном мире). И это даже для околонулевой конференции. Я лучше буду писать код, работать с людьми, делать "промышленное" исследование, а науку оставлю ребятам, которые в ней понимают и которым она доставляет удовольствие. 😇
Ссылочка на мою работу.
👍5🔥3🤡1
Танцы с бубном
На работе я и моя команда часто занимаемся разного рода шаманством! 🥷
Например, сейчас мы решаем проблемы питания на одной плате от стороннего производителя. При высоких нагрузках устройство просто отключается — это очень и очень плохо. 🙈
На сайте производителя документация так и говорит: "найдите резистор с номером 135 и удалите с микросхемы. Затем будет счастье и не будет проблем."
Как говорится, сказано — сделано, но проблемы есть:
1. Чтобы найти резистор 135, пришлось еще раз знатно документацию прошерстить;
2. Резистор-таки нашли (но это не точно) — только он меньше, чем сахаринка. Как теперь это выпаивать и соединять — понятия не имею. Но у нас есть стретегия, и мы будем её придерживаться.
Забавно то, что я так и не смог найти надпись 135 на резисторе. Является ли он 135-ым — покажет время.
Что-ж, как отпаяем — дам знать, помогло или нет :)
P.S. На первой картинке примерное местоположение резистора. На второй картинке — предполагаемый резистор в ультра увеличенном масштабе.
На работе я и моя команда часто занимаемся разного рода шаманством! 🥷
Например, сейчас мы решаем проблемы питания на одной плате от стороннего производителя. При высоких нагрузках устройство просто отключается — это очень и очень плохо. 🙈
На сайте производителя документация так и говорит: "найдите резистор с номером 135 и удалите с микросхемы. Затем будет счастье и не будет проблем."
Как говорится, сказано — сделано, но проблемы есть:
1. Чтобы найти резистор 135, пришлось еще раз знатно документацию прошерстить;
2. Резистор-таки нашли (но это не точно) — только он меньше, чем сахаринка. Как теперь это выпаивать и соединять — понятия не имею. Но у нас есть стретегия, и мы будем её придерживаться.
Забавно то, что я так и не смог найти надпись 135 на резисторе. Является ли он 135-ым — покажет время.
Что-ж, как отпаяем — дам знать, помогло или нет :)
P.S. На первой картинке примерное местоположение резистора. На второй картинке — предполагаемый резистор в ультра увеличенном масштабе.
🤯1🤡1
Нас обманывали, а мы и не заметили (Часть 1)
На днях я задумался, а можно ли как-то получить доступ к тому, к чему обычно нельзя просто так обратиться. Например, к
Определим простой класс с полем:
Шикарно. Теперь используем using declaration, чтобы в наследнике вытащить поле в
Заметим, что если мы сделаем поле у класса
Как бы теперь превратить
Ух, сложно. Попробуем это всё дело запустить:
Как видите, всё работает. Но есть проблемки — перемещение данных и всё такое. Как-то это не серьезно, что ли. Давайте усложним задачу и запретим перемещение:
Как же быть? Ну всё просто. Вернемся к первоначальному варианту класса
Заметим, что
И вот это уже магия. Здесь ничего не перемещалось, но при этом мы изменили данные, которые недоступны извне.
Это очень интересный трюк, который показывает силу языка, но я надеюсь, он никогда вам не понадобится. Все же мы сделали очень много допущений. Но это даже неважно. Необходимо понимать, что если скрыли данные — то в этом был смысл. И не нужно пытаться получить к ним доступ, если не дают.
P.S. Можете запустить это в godbolt.
#разработка
На днях я задумался, а можно ли как-то получить доступ к тому, к чему обычно нельзя просто так обратиться. Например, к
private полям класса, без его модификации в С++. Оказывается, при большом желании — да. Как это сделать, я расскажу в следующих сериях, а покамест ограничимся только protected полями. Определим простой класс с полем:
class A {
public:
int Get() const { // Чтобы выводить в консольку
return a;
}
protected:
int a = 10;
};Шикарно. Теперь используем using declaration, чтобы в наследнике вытащить поле в
public секцию примерно так: class B : public A {
public:
using A::a;
};Заметим, что если мы сделаем поле у класса
A — private, то такой трюк не получится сделать, потому что приватные поля при наследовании всегда остаются приватными. Как бы теперь превратить
A в B. Первое, что приходит в голову — использовать move-семантику (т.е. будем не копировать данные, а именно перемещать). Поэтому превращение можно сделать так: class B : public A {
public:
using A::a;
B(A&& value) : A(std::forward<A>(value)) {} // паттерн перемещения
A ConvertToA() { // функция для конвертации обратно в A
A a = std::move(*this); // Перемещаем себя же обратно в A
return a; // Возвращаем новый A
}
};Ух, сложно. Попробуем это всё дело запустить:
A a; // Создаем переменную
std::cout << a.Get() << std::endl; // выведет 10
{
B b(std::move(a));
b.a = 20;
a = b.ConvertToA();
}
std::cout << a.Get() << std::endl; // выведет 20Как видите, всё работает. Но есть проблемки — перемещение данных и всё такое. Как-то это не серьезно, что ли. Давайте усложним задачу и запретим перемещение:
class A2 {
public:
int Get() const {
return a;
}
A2() = default; // нужно определить конструктор по умолчанию
A2(A2&&) = delete; // удаляем перемещение, т.е. std::move не воспользоваться
protected:
int a = 10;
};Как же быть? Ну всё просто. Вернемся к первоначальному варианту класса
B, только назовем его C:class C : public A2 {
public:
using A2::a;
};Заметим, что
C не добавляет никаких данных, а поэтому практически всегда его представление в памяти совпадает с A2. Тогда можно попробовать воспользоваться reinterpret_cast: {
A2 a2;
std::cout << a2.Get() << std::endl; // выведет 10
C& c = reinterpret_cast<C&>(a2);
c.a = 30;
std::cout << a2.Get() << std::endl; // выведет 30
}
И вот это уже магия. Здесь ничего не перемещалось, но при этом мы изменили данные, которые недоступны извне.
Это очень интересный трюк, который показывает силу языка, но я надеюсь, он никогда вам не понадобится. Все же мы сделали очень много допущений. Но это даже неважно. Необходимо понимать, что если скрыли данные — то в этом был смысл. И не нужно пытаться получить к ним доступ, если не дают.
P.S. Можете запустить это в godbolt.
#разработка
🤔2🤯2👍1🤡1
Нас обманывали, а мы и не заметили (Часть 2)
Рассказываю, как поменять приватное поле класса. Возьмем класс
Давайте подменим значения поля
Что произошло 🤯? Мы представили область памяти, где лежит объект
Пора раскрывать карты и поговорить немного о том, как объект класса располагается в памяти ПК. Символом
Объект выше показанного класса будет располагаться в пямяти как 4 байта (почти всегда):
Почему так? Потому что
Давайте теперь в классе
Запустим тот же код:
ХАХ! А ничего не работает 😤! Обманул вас Антон! На самом деле нет. Давайте по порядку. Когда мы представляем объект в виде массива чисел, мы говорим компилятору: фрагментируй память по 4 байта (по размеру типа
Получается две чиселки типа
Тэк-с...🤨 Что-то явно пошло не так. Или так?
На самом деле мы с вами столкнулись с самой большой болью
Куда бОльшие проблемы появляются, когда путем перезатераний памяти мы теряем место, где выделили какую-то память. Происходит утечка памяти (ваши игры именно так и вылетают) — с одной стороны, место в памяти вроде как не нужно больше, с другой стороны — операционная система не дает заполнить это место, потому что мы там ничего не освободили, а сделать этого не можем, потому что место потеряли 😂.
Все эти
Все операции выше — сугубо в учебных целях. На практике это пригождается в очень специфических кейсах и надо иметь четкие гарантии и представление, что все будет именно так, как задумывалось. Иначе поменяем
В следующем посте я расскажу подробнее про то, как классы устроены в памяти. Там не всё так просто!
P.S. Ссылочка на godbolt.
#разработка
Рассказываю, как поменять приватное поле класса. Возьмем класс
A из поста выше, заменим protected секцию на private:class A {
public:
int Get() const { // Чтобы выводить в консольку
return a;
}
private:
int a = 10;
};Давайте подменим значения поля
a с помощью нехитрого кода: A a;
std::cout << a.Get() << std::endl; // выведет 10
static_cast<int*>(static_cast<void*>(&a))[0] = 20;
std::cout << a.Get() << std::endl; // выведет 20Что произошло 🤯? Мы представили область памяти, где лежит объект
A, в виде массива int — чиселок. Внутри только одно число, а потому обращаясь к нулевому элементу типа int, мы обращаемся к содержимому объекта a и меняем его. Здесь нам повезло — мы знали, что у класса A поле типа int. Пора раскрывать карты и поговорить немного о том, как объект класса располагается в памяти ПК. Символом
# я буду означать 1 байт памяти. Объект выше показанного класса будет располагаться в пямяти как 4 байта (почти всегда):
####Почему так? Потому что
int на современных ПК занимает 4 байта. В этом классе больше нет никакой информации (поверьте, её бывает очень много). Все вызовы функций определяются еще на этапе компиляции. Именно поэтому, по другому представив объект (в виде массива int) — мы с легкостью заменили переменную в объекте 🥲.Давайте теперь в классе
A заменим int на double, назовем этот класс B. На современных ПК double занимает 8 байт и выглядит так: ########
Запустим тот же код:
B b;
std::cout << b.Get() << std::endl; // выведет 10
static_cast<int*>(static_cast<void*>(&b))[0] = 20;
std::cout << b.Get() << std::endl; // выведет 10ХАХ! А ничего не работает 😤! Обманул вас Антон! На самом деле нет. Давайте по порядку. Когда мы представляем объект в виде массива чисел, мы говорим компилятору: фрагментируй память по 4 байта (по размеру типа
int), поэтому пямять объекта разобъется так: #### ####Получается две чиселки типа
int. Ну хорошо, мы поменяли первую чиселку, должно же было что-то поменяться. Давайте чтоли попробуем вторую чиселку поменять:
static_cast<int*>(static_cast<void*>(&b))[1] = 20;
std::cout << b.Get() << std::endl; // выведет 4.24399e-313Тэк-с...🤨 Что-то явно пошло не так. Или так?
На самом деле мы с вами столкнулись с самой большой болью
C++ разработчиков — работой с памятью 😩. Программист в этом языке может напрямую менять значения в памяти, но нередко это делается неправильно 🤷. Например, как я намеренно это сделал, предствив число double в виде двух int. Тип double намного сложнее, подробнее про это можно почитать здесь. И просто так там значение не подменить. Куда бОльшие проблемы появляются, когда путем перезатераний памяти мы теряем место, где выделили какую-то память. Происходит утечка памяти (ваши игры именно так и вылетают) — с одной стороны, место в памяти вроде как не нужно больше, с другой стороны — операционная система не дает заполнить это место, потому что мы там ничего не освободили, а сделать этого не можем, потому что место потеряли 😂.
Все эти
private, protected секции в языке — это некоторые гарантии языка на уровне абстракций для классов. Но как только переходим на уровень, где происходит работа с памятью напрямую — никакая гарантия языка не поможет. Насколько я знаю, именно за счет того, что разработчики не позаботились о дополнительном сокрытии переменных, с помощью ArtMoney в играх можно было хакнуть себе ресурсов побольше — программа просто лезла в область памяти вашей программы и находила байты, в которых лежат чиселки, похожие на заданные 🥷.Все операции выше — сугубо в учебных целях. На практике это пригождается в очень специфических кейсах и надо иметь четкие гарантии и представление, что все будет именно так, как задумывалось. Иначе поменяем
int, а нужно было double. Лично я сталкивался с этим один раз в жизни, когда связывал Objective-C и C++ для алгоритмов ray casting. В следующем посте я расскажу подробнее про то, как классы устроены в памяти. Там не всё так просто!
P.S. Ссылочка на godbolt.
#разработка
🔥3👍2🤔1😱1🤡1
Выравние или то, на что обычно забивают 🙈
Как я уже упомянул в прошлом посте: классы — штука непростая. И сейчас я постараюсь описать некоторые интересные чудеса.
Для начала интересно узнать, каков размер пустого класса? Такого как этот:
Если вы скажите
Забавно то, что если мы сделаем следующий класс:
Чиселка в int означает число бит. Например:
то его размер тоже будет
Пойдем немного дальше. Объявим следующий класс:
С точки зрения логики здесь
Эта структура будет занимать целых
Но иногда нам всё же нужно получить максимально сжатую структуру. В
В этом случае структура
Подробнее про объекты можно почитать здесь.
Посмотреть на выводы можно здесь.
#разработка
Как я уже упомянул в прошлом посте: классы — штука непростая. И сейчас я постараюсь описать некоторые интересные чудеса.
Для начала интересно узнать, каков размер пустого класса? Такого как этот:
class A {};Если вы скажите
0 — вы будете неправы. Или правы? Или нет?😅 С точки зрения теории размер правда должен быть равен 0. Но объекты класса нужно между собой различать, даже если класс пустой. Это значит, что какую-то память да выделить надо. По стандарту минимальный размер объекта — 1 байт. Это вам и выдаст sifeof(A) — команда, по которой можно узнать размер объекта/класса в C++.Забавно то, что если мы сделаем следующий класс:
class B {
int8_t b;
}Чиселка в int означает число бит. Например:
int8_t — это 8 бит или 1 байт; int32_t — это 32 бита или 4 байта. Подробнее про такие типы здесь.то его размер тоже будет
1 байт. Просто в случае, когда класс пустой — нам память нужна просто для того, чтобы различать объекты. В случае класса B нам уже нужно хранить данные.😇 Пойдем немного дальше. Объявим следующий класс:
class C {
int32_t a;
int8_t b;
int32_t c;
};С точки зрения логики здесь
9 байт. Но на самом деле будет 12 байт. Это происходит из-за выравнивания по ширине максимального фундаментального типа. Выравнивание необходимо для более быстрого чтения структуры и доступа с к данным. Но что в реальной практике достаточно часто можно увидеть, так классы пишут по следующему примеру: class D {
int32_t a;
int8_t b;
int32_t c;
int8_t d;
};
Эта структура будет занимать целых
16 байт, в то время как реальных данных тут на 10 байт 😡. Всё остальное — это выравнивание. Поменяйте c и d местами — получите 12 байт, бесплатно без регистрации и смс 🗿. Но иногда нам всё же нужно получить максимально сжатую структуру. В
C++ это можно сделать с помощью pragma pack:#pragma pack(push, 1)
class D2 {
int32_t a;
int8_t b;
int32_t c;
int8_t d;
};
#pragma pack(pop)
В этом случае структура
D2 будет точно иметь 10 байт 🥷. Но производительность системы может упасть, из-за того, что не всегда поддерживаются быстрые операции со структурурами, у которых убрали выравнивание. Так что баланс соблюден — либо побыстрее, либо поменьше.Подробнее про объекты можно почитать здесь.
Посмотреть на выводы можно здесь.
#разработка
👍3🔥1🤯1🤡1
GIT Анимашки
В жизни каждого из нас возникает период, когда необходимо делиться своими знаниями с новыми коллегами или новичками 👶. На такие случаи я собираю отдельную библиотечку, в которой храню полезные ссылочки 🤫.
Тут я подумал, что может быть и вам тоже будет интересно, поэтому время от времени буду разбавлять свои технические посты такими ресурсами. 😇
Одна из больших болей у начинающих в разработке — это работа с VCS (version control system). Если кратко — это инструмент, который позволяет хранить не только сами файлы, но и историю их изменений. Это очень удобно для текстовых форматов данных — можно понять, кто, когда и зачем добавил ту или иную строчку. Для больших файлов (3D модели, видео, аудио, картинки) существует GIT-LFS. У себя на работе мы используем GIT и сервис для удобного взаимодействия с ним — GitLab.
На днях я наткнулся на интересный пост с очень красивыми анимациями того, как работают основные и полезные команды Git.
Добавляйте себе в закладки!💫
#полезное #управление
В жизни каждого из нас возникает период, когда необходимо делиться своими знаниями с новыми коллегами или новичками 👶. На такие случаи я собираю отдельную библиотечку, в которой храню полезные ссылочки 🤫.
Тут я подумал, что может быть и вам тоже будет интересно, поэтому время от времени буду разбавлять свои технические посты такими ресурсами. 😇
Одна из больших болей у начинающих в разработке — это работа с VCS (version control system). Если кратко — это инструмент, который позволяет хранить не только сами файлы, но и историю их изменений. Это очень удобно для текстовых форматов данных — можно понять, кто, когда и зачем добавил ту или иную строчку. Для больших файлов (3D модели, видео, аудио, картинки) существует GIT-LFS. У себя на работе мы используем GIT и сервис для удобного взаимодействия с ним — GitLab.
На днях я наткнулся на интересный пост с очень красивыми анимациями того, как работают основные и полезные команды Git.
Добавляйте себе в закладки!💫
#полезное #управление
👍3🔥3🤡1
Инициализация весов в нейронных сетях
Один из самых очевидных и недооцененных моментов во время подготовки нейронной сети к обучению — это инициализация её весов. 🤷
Для справки: можете понимать нейронные сети как набор функций и матриц. Вот эти матрицы обычно называются весами. Т.к. слоёв в нейронной сети много — то и матриц тоже много (по крайней мере одна на слой). Тогда если
Дело всё в том, что если в жизни для того, чтобы начать дело, нужно просто начать, то в машинном обучении нужно еще подготовиться к этому всему.🗿 Я опускаю моменты, связанные с подговкой данных, которые являются наиболее важными.
Допустим мы все сделали, написали весь код, подготовили данные, продебажили и поняли что всё в целом работает. И даже что-то учится и нейронная сеть выдает адекватные результаты☺️. Но не такие, какие хотелось бы. А еще учится просто ужасно долго (относительно 🥲). До первых адекватных результатов — 20 часов. 😢
Начинаем разбираться, как так, а что случилось? Или всё ок?🤔 И самая первая классика — забили/забыли/не подумали про инициализацию весов. Исправляем, запускаем и ого — теперь сеточка показывает первые результаты через 5 часов, а метрики уже показывают новые рекорды 💫. А казалось бы — какая-то инициализация весов, кто бы мог подумать.
В этом замечательном посте описано с формулами и картинками, почему важна инициализация весов.
А вам желаю я сходимости весов и градиентов без затуханий и взрывов!🤗
#разработка
Один из самых очевидных и недооцененных моментов во время подготовки нейронной сети к обучению — это инициализация её весов. 🤷
Для справки: можете понимать нейронные сети как набор функций и матриц. Вот эти матрицы обычно называются весами. Т.к. слоёв в нейронной сети много — то и матриц тоже много (по крайней мере одна на слой). Тогда если
X — это какой-то вход (картинка или что-то другое), а w — это веса на одном слое, то простейшая нейронная сеть — это fun(Xw), где fun — это какая-то функция. Дело всё в том, что если в жизни для того, чтобы начать дело, нужно просто начать, то в машинном обучении нужно еще подготовиться к этому всему.🗿 Я опускаю моменты, связанные с подговкой данных, которые являются наиболее важными.
Допустим мы все сделали, написали весь код, подготовили данные, продебажили и поняли что всё в целом работает. И даже что-то учится и нейронная сеть выдает адекватные результаты☺️. Но не такие, какие хотелось бы. А еще учится просто ужасно долго (относительно 🥲). До первых адекватных результатов — 20 часов. 😢
Начинаем разбираться, как так, а что случилось? Или всё ок?🤔 И самая первая классика — забили/забыли/не подумали про инициализацию весов. Исправляем, запускаем и ого — теперь сеточка показывает первые результаты через 5 часов, а метрики уже показывают новые рекорды 💫. А казалось бы — какая-то инициализация весов, кто бы мог подумать.
В этом замечательном посте описано с формулами и картинками, почему важна инициализация весов.
А вам желаю я сходимости весов и градиентов без затуханий и взрывов!🤗
#разработка
Aditya Rana Blog
Don’t Trust PyTorch to Initialize Your Variables
why does good initialization matter in neural networks and what are vanishing gradients
🔥2🤯1🤡1
C++ Zero Cost Conf 2022
Начиная с прошлого года я обязательно посещаю конференцию от Яндекса C++ Zero Cost Conf. Это возможность послушать бесплатно доклады от ребят, которые делают один из самых сложных и больших 🤯 highload на рынке России и, наверное, даже в СНГ. В этом году она будет 30 июля.
Я бы не стал выделять какие-то отдельные доклады, потому что сейчас программа выглядит очень сбалансировано и практически на все доклады можно попасть без перекрытий. Но лично я с удовольствием посмотрю на доклад от ClickHouse (просто люблю доклады от них). 😇
Регистрируйтесь на конференцию. Даже если вы не практикующий плюсовик, я думаю, вам будет интересно и полезно, как устроены сложные системы и с чем разработчики сталкиваются в большом highload! 🥷
#разработка
Начиная с прошлого года я обязательно посещаю конференцию от Яндекса C++ Zero Cost Conf. Это возможность послушать бесплатно доклады от ребят, которые делают один из самых сложных и больших 🤯 highload на рынке России и, наверное, даже в СНГ. В этом году она будет 30 июля.
Я бы не стал выделять какие-то отдельные доклады, потому что сейчас программа выглядит очень сбалансировано и практически на все доклады можно попасть без перекрытий. Но лично я с удовольствием посмотрю на доклад от ClickHouse (просто люблю доклады от них). 😇
Регистрируйтесь на конференцию. Даже если вы не практикующий плюсовик, я думаю, вам будет интересно и полезно, как устроены сложные системы и с чем разработчики сталкиваются в большом highload! 🥷
#разработка
👍3🔥1😱1🤡1
Addressof
Иногда, когда мы люди пишут библиотеки на
В нём я добавил один метод, о котором я расскажу позже. Как я уже рассказывал в посте, мы можем изменить приватные поля класса. Давайте изменим поле
Странно, скажете вы 🤨. И правда — вроде обратились к первому элементу и хотели поменять его. А в итоге поменяли второй. Ну чушь какая-то. В чем же дело?
А проблема как раз в новом методе. Он переопределяет оператор взятия указателя
Но как же избежать такого поведения? Неужели ребята из комитета
Это что, магия 💫??? Почему этот метод работает, а оператор
Можно было попробовать
Почему здесь
Теперь нам осталось просто 🤗 превратить это в указатель на
Поздравляю нас! Мы это сделали! Нооо.. Есть одна проблема ☺️. Допустим если переменная
Как вы поняли, мы тут не можем просто взять и превратить всё в
Вот теперь это будет работать в любом случае!☺️ Так эта функция примерно устроена в стандартной библиотеке. Я был очень сильно удивлен этому костылю 🤯!
В конце я хочу лишь сказать, что переопределять оператор
P.S. Ссылочка на Godbolt
#разработка
Иногда, когда мы люди пишут библиотеки на
C++ (можно сказать отдельный самодостаточный модуль приложения), важно строго следить за тем, что ты делаешь в коде 😅. Можно просто на раз два выстрелить себе в ногу 🗿: мы это уже видели в множестве постов выше (тык, тык). Вернемся к нашему любимому примеру: class A {
public:
int *operator&() { return &b_; }
void Print() const { std::cout << a_ << ' ' << b_ << std::endl; }
private:
int a_ = 100;
int b_ = 200;
};В нём я добавил один метод, о котором я расскажу позже. Как я уже рассказывал в посте, мы можем изменить приватные поля класса. Давайте изменим поле
a_: A a{};
a.Print(); // выведет 100 200
static_cast<int *>(static_cast<void *>(&a))[0] = 20;
a.Print(); // выведет 100 20Странно, скажете вы 🤨. И правда — вроде обратились к первому элементу и хотели поменять его. А в итоге поменяли второй. Ну чушь какая-то. В чем же дело?
А проблема как раз в новом методе. Он переопределяет оператор взятия указателя
&. Когда разработчик его переопределяет, вместо возврата указателя на область памяти, где лежит объект, будет вызван метод. А он возвращает указатель на b_. Поэтому и меняется значение b_ 😢. Но как же избежать такого поведения? Неужели ребята из комитета
C++ не продумали и оставили такую дыру? На самом деле нет — есть std::addressof — этот метод как раз и помогает нам избежать проблемы 🥷. Смотрите сами: A b{};
b.Print(); // выведет 100 200
static_cast<int *>(static_cast<void *>(std::addressof(b)))[0] = 20;
b.Print(); // выведет 20 200Это что, магия 💫??? Почему этот метод работает, а оператор
& нет? Давайте подумаем, как можно такое написать. Для начала вспомним, что мы не можем писать оператор & перед переменной — это приведет к вызову переопределенного метода 🤓. Можно было попробовать
static_cast и const_cast, но там нужно как-то привести всё к void*. А этого мы сделать не можем, потому что не можем получить указатель. Остается reinterpret_cast. Предлагаю сделать тогда приведение к char &: reinterpret_cast<char &>(b) Почему здесь
&? Потому что без него компилятор будет ругаться и говорить, что привести типы не может. Так устроен reinterpret_cast 😅. После преобразования мы получили ссылочный тип char& и вот от него можно получить уже указатель:&reinterpret_cast<char &>(b)Теперь нам осталось просто 🤗 превратить это в указатель на
A. Делаем: reinterpret_cast<A *>(&reinterpret_cast<char &>(b))
Поздравляю нас! Мы это сделали! Нооо.. Есть одна проблема ☺️. Допустим если переменная
b — константная? Или volatile? reinterpret_cast в этом случае не будет работать. Чтобы обеспечить поддержку двух этих ключевых слов — нам нужно включить их в тип, т.е. сделать так: reinterpret_cast<const volatile char &>(b)Как вы поняли, мы тут не можем просто взять и превратить всё в
A *. Нужно будет прокидывать ключевые слова const и volatile. А нам этого точно не нужно. К счастью, const_cast умеет их убирать. Тогда используя его, получим следующую реализацию addressof: reinterpret_cast<A *>(const_cast<char *>(&reinterpret_cast<const volatile char &>(b))) Вот теперь это будет работать в любом случае!☺️ Так эта функция примерно устроена в стандартной библиотеке. Я был очень сильно удивлен этому костылю 🤯!
В конце я хочу лишь сказать, что переопределять оператор
& не стоит 🤨. Любой компилятор или статический анализатор подчеркнет и выведет предупреждение. Но порой необходимо делать такие вещи. А поэтому при разработке библиотек нужно учитывать даже такой, очень неявный момент.😓P.S. Ссылочка на Godbolt
#разработка
👍1🔥1🤯1🤡1
C++ для самых маленьких 😄 и С++ для тех, кому за 300 😢
В последнее время нет сил что-либо писать. Да что уж там говорить — нет сил что-либо делать. Какое-то эмоциональное выгорание, которое я никак понять не могу🥺 . Но между делом я стараюсь уделять время своему любимому хобби — программированию 👨💻 .
Совсем недавно я наткнулся на конспекты курса по C++ кафедры КТ (компьютерные технологии) Университета ИТМО🧑🎓 . Они в целом хороши — дают первичное понимание языка, того, как это работает и что с этим можно делать. Жаль, что мемы не вставили — тогда был бы лучший курс для самых маленьких 🍷 , имхо.
Сейчас я погружаюсь детальнее в то, как работают приложеньки на Unix-подобных системах. В частности, как они загружаются в оперативку, как находят сторонние зависимости и т.д. Казалось бы — при чем тут C++, а на самом деле есть повод задуматься😢 . Мы можем оптимизировать поиск сторонних зависимостей (как во время компиляции, так и во время исполнения), можем оптимизировать загрузку в оперативку. А это все сказывается на пользовательское ощущение от использования наших приложений (вас же тоже бесит то, как долго грузится spotify или slack??? 😡 ).
Куда важнее ситуация, когда мы делаем приложение на highload backend😆 , где важно не только время на ответ, но и также, как быстро приложение может восстановиться после падения. Поэтому понимание того, как работает наше приложение от момента нажатия на enter — очень важно, и классно, когда мы можем управлять этим процессом на своем языке программирования.
"Я как будто бы уже давно глубокий старец, бессмертный, ну или там уже почти бессмертный" стараюсь изучать эти процессы, чтобы делать мои приложение быстрее, лучше. Я "ищу только одного — покоя, умиротворения и вот этой гармонии, от слияния с бесконечно вечным, от созерцания великого фрактального подобия и от вот этого замечательного всеединства существа"😄 .
В последнее время нет сил что-либо писать. Да что уж там говорить — нет сил что-либо делать. Какое-то эмоциональное выгорание, которое я никак понять не могу
Совсем недавно я наткнулся на конспекты курса по C++ кафедры КТ (компьютерные технологии) Университета ИТМО
Сейчас я погружаюсь детальнее в то, как работают приложеньки на Unix-подобных системах. В частности, как они загружаются в оперативку, как находят сторонние зависимости и т.д. Казалось бы — при чем тут C++, а на самом деле есть повод задуматься
Куда важнее ситуация, когда мы делаем приложение на highload backend
"Я как будто бы уже давно глубокий старец, бессмертный, ну или там уже почти бессмертный" стараюсь изучать эти процессы, чтобы делать мои приложение быстрее, лучше. Я "ищу только одного — покоя, умиротворения и вот этой гармонии, от слияния с бесконечно вечным, от созерцания великого фрактального подобия и от вот этого замечательного всеединства существа"
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1🤯1🤡1
Новая эпоха 👨💻
С сегодняшнего дня я сотрудник компании Яндекс. Буду помогать команде улучшать качество сервисов, применяя свои знания в области CV DL и C++.
Думаю, будет много интересного, чем можно будет в том числе и поделиться с вами! А пока буду вливаться в процессы :)
С сегодняшнего дня я сотрудник компании Яндекс. Буду помогать команде улучшать качество сервисов, применяя свои знания в области CV DL и C++.
Думаю, будет много интересного, чем можно будет в том числе и поделиться с вами! А пока буду вливаться в процессы :)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥5💩4😱1😢1🤡1