...

суббота, 21 июля 2018 г.

Рассуждения о перспективах в Телекоме

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

Основная характеристика сегодняшнего телекоммуникационного рынка — постоянное снижение рентабельности бизнеса с 2008 года и усиление этой тенденции с 2014 года. К этому приводят следующие внутренние причины:
  • перенасыщение рынка услугами связи, не охваченных услугами клиентов практически нет, особенно в городах;
  • высокая конкуренция на рынке, только на рынке Московского региона около 7000 операторов связи.

Ну и естественно, есть и внешние причины:

  • Закон «Яровой», жёсткие требования по реализация мероприятий СОРМ. Срочная необходимость новых серьёзных капитальных вложений в сетевую инфраструктуру.
  • Постоянный кризис во всей экономике государства. Санкции, рубль падает, доллар растёт, стоимость нефти низкая, а стоимость бензина повышается. Официально инфляция не очень высокая, но стоимость услуг ЖКХ, аренды, электроэнергии и т. д. постоянно растёт.
  • Популярные нынче инициативы ЖКХ, типа «чистое небо» или благоустройство территории, а также демонизация операторов связи в СМИ по данной теме. Причём никто не задумывается, а есть ли у оператора реальная техническая и экономическая возможность убрать свой воздушно-кабельный переход под землю или восстановить линейно-кабельное сооружение (кабельную канализацию) в конкретном месте.

Историческая притча, рассказанная на одном из форумов

На фоне этой не очень радостной картины вспоминается история, рассказанная Генеральным директором УфаНет: «Во время реконкисты Испании одного султана взяли в плен вместе с семьёй. Решили его повесить, а жену и детей в живых оставить. Султан начал умолять оставить его в живых. Услышав это, жена султана сказала мужу: «Если бы ты дрался, как мужчина, то сейчас не умирал бы как собака». Действительно, раньше основной императив всех форумов и выставок для операторов связи был — «как заработать». Сейчас — «как выжить».


Что же остаётся делать оператору в данной ситуации?

На мой взгляд в текущей ситуации, перспектив у оператора связи несколько:
  1. Продать свой бизнес кому-нибудь. Желающие есть и их не мало. Крупные отечественные операторы планово расширяют свой бизнес или убирают конкурентов, отчитываются перед инвесторами об увеличении капитализации компании. Иностранные операторы заходят на рынок. Кто-то хочет войти в телеком-бизнес. Однако с каждым годом стоимость оператора становится на удивление ниже, хотя сеть оператора становится больше.
  2. Поднять цены на свои услуги. Тем самым — попытаться увеличить рентабельность. Сие конечно чревато потерей клиентов и потерей доли рынка. Но сразу все клиенты не уйдут.
  3. Ничего не делать. Тоже вариант. Рынок динамичен, авось пронесет и наступят «тучные времена». Либо станет понятно, что делать и куда срочно бежать, догонять тех, кто что-то делал.
  4. Заняться параллельно какой-нибудь другой деятельностью, например, как один московский оператор, клинингом. А что, приходит монтажник подключать клиента, заодно и уборку квартиры сделает. Или ИТ-темами вплотную заняться, начать софт разрабатывать, благо ИТ-блок в телекоме обычно представлен хорошо. Или заняться популярной сейчас темой, связанной с криптовалютой.
  5. Придумать свою «фишку», которая «выстрелит» и приведет компанию к «светлому коммунистическому, капиталистическому, социалистическому (нужное подчеркнуть) будущему». Как вариант — свой ТВ-канал создать или снимать свои «стримы» для Yutube, надо только соответствующую тематическую нишу найти.


В любом случае потребуется серьёзно пересмотреть свою деятельность и ещё раз оценить рынок. Но прежде — ответить себе на вопрос: что изменится в этом мире, если конкретная телекоммуникационная компания перестанет существовать?

Let's block ads! (Why?)

[Из песочницы] Мой опыт трудоустройства на роль Agile Coach в Европе, часть первая

Всем привет!
Меня зовут Денис, мне 27 лет и я работаю Agile Coach в компании N26 (Берлин, Германия) — самом быстрорастущем мобильном банке в Европе.

image

Прежде чем переехать в Берлин в апреле 2018 года, я провел 9 месяцев в поисках подходящего места работы в Европе. За это время я успел:
— пройти порядка 20 интервью;
— дойти до финального этапа с 7 компаниями*;
— получить 3 оффера.

Для этого мне пришлось совершить порядка 18 перелетов и посетить 3 страны (Германия, Нидерланды, Австрия).

Рассказать о своём опыте меня сподвигло несколько факторов:
1) Высокий интерес к подобным материалам в IT-сообществе при практически полном отсутствии историй “тракторизма” от специалистов в области Agile на просторах сети;
2) Стремление поделиться с сообществом полученными инсайдами о том, как же выглядит «тот самый» Agile в Европе;
3) Желание зафиксировать все пережитое для себя лично, пока краски не потускнели и воспоминания еще живы.

* В данной статье Вы не встретите прямого указания на компании, с которыми я успел пообщаться, но общее описание контекста я постараюсь все же давать.

Пролог


Желание выбраться за пределы горячо любимой Родины терзало меня довольно продолжительное время. Активный поиск вакансий и прохождение собеседований я начал летом 2016 года, когда совокупность личных, экономических и других факторов, а также желание активно развиваться в выбранном направлении, подтолкнули меня сделать первый шаг.

На тот момент мой опыт знакомства с Agile составлял порядка двух лет и я успел предпринять несколько попыток его применения на практике с разной степенью успешности. Это вылилось в опыт работы с 2 Scrum командами в качестве Scrum Master, запуска Agile-трансформации в организации, а также несколько попыток выстроить Kanban на паре других проектов. К моему большому счастью, суть проектов, находившихся в разработке в компании, где я трудился на тот момент, позволяла и даже вынуждала реально формировать кросс-функциональные команды, в которых полноправно участвовали как Back-End, Front-End и Mobile dev специалисты, так и QA инженеры и дизайнеры.

Первым направлением поисков работы была выбрана Польша, Чехия, Германия и Прибалтика. В итоге же я оказался на Кипре, где удачно и с большим удовольствием трудился по своему направлению в течение 18 месяцев. Условия работы и коллектив устраивали меня полностью, но сама жизнь на Кипре — нет. Я не буду вдаваться в детали, так как все это вопрос субъективного восприятия, но меня тянуло пожить в более развитой стране. Дополнительным фактором было желание работать в полностью англоговорящем коллективе (своеобразный челлендж) и иметь возможность развиваться, принимая участие в жизни местного Agile-коммьюнити, признаков которого на Кипре я не обнаружил.

image

Май 2017 *

Поворотным моментом стала длительная поездка на конференцию XP Cologne 2017 — после недели проведенной в Кёльне в середине мая, желание продолжать жить на Кипре отбило начисто. Вдобавок и сама конференция привела к мысли, что уровень моего владения вопросом и понимания многих вещей вполне удовлетворяет европейскому рынку труда. Проблемы языкового барьера для меня также не стояло, так как мое судьбоносное знакомство с английским языком началось еще в пятилетнем возрасте.

* Чтобы ориентироваться в моей истории было проще, я буду указывать временные ориентиры на протяжении всей истории

Акт первый: «Начало поисков и первые успехи первый урок»


Июнь 2017.

Первым шагом по возвращении на остров стало обновление и существенная переработка резюме. Сразу скажу что первая попытка адаптировать его под активно продвигаемый во многих Telegram-каналах и блогах “немецкий формат” (Lebenslauf + Bewerbungsanschreiben + Empfehlungen) не принесло абсолютно никакого результата и доля назначенных собеседований относительно общего числа оставленных откликов была крайне невысокой. Причина была банальна — IT рынок Германии состоит как минимум на 60% из экспатов и большинство HR-ов, будучи иностранцами, банально не имели желания разбираться с моей писаниной на немецком. В итоге я оптимизировал свой профиль на LinkedIn и стал использовать его PDF-версию в качестве CV.

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

Июль 2017

Классический процесс рекрутинга почти во всех компаниях, с которыми я имел удовольствие общаться, состоял из 3 этапов:

  • 30-минутное интервью с рекрутером или другим представителем HR департамента;
  • 60- или 90-минутное интервью с будущими коллегами в расширенном составе (действующий Agile Coach; Product Owner или другой менеджер со стороны бизнеса; разработчик или Team Lead)
  • On-site интервью, продолжительностью от 3 до 6 часов и включающее в себя встречи с разными сотрудниками компании и выполнение различных заданий, в частности проведение Ретроспективы у одной из существующих команд. (так было в 3 случаях из 7) Заканчивался процесс короткой беседой с рекрутером, где у меня спрашивали впечатление о проведенном дне и информировали о сроках предоставления решения.

Как и в случае с большинством разработчиков, чьи статьи Вы наверняка уже читали, все расходы по организации посещения офиса брала на себя компания (перелеты, отель, завтрак в отеле). Отдельную прелесть подобных собеседований была в том, что прямые рейсы в Берлин с Кипра являются большой редкостью и я не раз оказывался в ситуации, когда время проведенное в дороге могло доходить до 10-12 часов с учетом пересадок. Все это ради 1-1,5 дней в пункте назначения, из которых 3-6 часов ты проводишь на собеседовании.

Так было и в тот раз — вылетев с Кипра в районе 12 часов дня, я приземлился в берлинском аэропорте Тегель лишь в районе 9 часов вечера и не имел ни сил, ни желания проводить осмотр достопримечательностей.

Как Вы уже должно быть поняли, первое собеседование я провалил. Продолжалось оно порядка 5 часов, по итогам которых я чувствовал себя вымотанным, а до обратного рейса оставалось всего 4 часа. При этом, общее впечатление от собеседования было крайне позитивным и я уже предвкушал надвигающийся переезд в столицу ФРГ. Дополнительным фактором была сама компания — один из лидеров на международном рынке навигации и геолокации, активно применяющий такие интересные для меня технологии, как Machine Learning, и, к тому же, имеющий ряд внутренних стартапов в области autonomous driving, wearables и IoT. “Будущие коллеги” были крайне доброжелательны и открыты, в целом, выражали оптимизм и внушали уверенность в светлое будущее.

В начале своей статьи я пообещал также делиться инсайдами о состоянии Agile в Европе. Большинство команд в берлинском офисе данной компании не были кросс-функциональными, т.к. офис отвечал исключительно за навигационную составляющую продукта. Средний размер команды — 6-8 человек. Со слов тех, с кем мне удалось пообщаться, большинство команд следовало «чистому Scrum» с применением технических практик из XP, однако некоторые, считавшиеся более зрелыми, также применяли элементы Kanban. Каждая команда имела закрепленного за ней Product Owner. Scrum Master «шарились» между 2-3 командами. Предпочтение отдавалось ведению Бэклога Продукта и Спринта на физической доске. Это отразилось, в том числе, и на заданиях в ходе собеседования: мне было предложено продемонстрировать какой я вижу «идеальную» физическую доску (колонки, WIP лимиты и прочее), а также составить формулу для вычисления Velocity команды в Google Spreadsheet. Визуализации иных артефактов команд, таких как Definition of Done, Working Agreements и прочие обнаружить не удалось.

Пришедший спустя 2 дня отказ стал для меня неожиданностью. Но самым неприятным была его форма — полученный мной email был стандартным темплейтом, который обычно рассылают кандидатам, получившим отказ еще на уровне CV скрининга. Учитывая количество потраченного на собеседования времени, а также достаточно стрессовую поездку на очное собеседование, я явно рассчитывал на нечто большее — как минимум, на какой-то детализированный фидбэк, который мог бы указать мне на “точки роста” и стать подспорьем в дальнейших поисках.

Мое письмо с просьбой дать хотя бы какой-то фидбэк осталось проигнорированным и с этого момента саму компанию я добавил в персональный “чёрный список”.

Акт второй: “Немецкий орднунг или сказка о потерянном времени”.

image

Тем не менее, урок из произошедшего был мною вынесен и поиски продолжились. Счет откликов на вакансии шел на десятки и упомнить все компании, куда я откликнулся, становилось практически нереально. Следующая “зацепка” пришла в самый неожиданный момент — в мой день рождения, который мы с женой с удовольствием проводили в парижском Диснейленде. Звонила девушка из рекрутингового агентства и сообщила что мое CV заинтересовало одного из их клиентов и они готовы назначить первое собеседование.

Тут стоит сделать небольшое отступление и указать что помимо стремления к новым знаниям и улучшению условий жизни, на поиски работы, в первую очередь, меня подтолкнуло желание поучаствовать в работе над продуктом, имеющим реальную социальную значимость и пользу. Заинтересованная мной компания занималась разработкой и поддержкой собственного мобильного приложения, агрегирующего предложения от десятков каршеринг-сервисов, а также прокатов электрических мопедов и велосипедов в крупнейших городах Европы и США. Прожив 25 лет своей жизни в Краснодаре, занимающем 24 место в топ-100 городов мира с самыми большими автомобильными пробками по итогам 2017 года, я прекрасно понимал какой вклад Sharing Economy способна внести в улучшение городской инфраструктуры.

Помимо интересного продукта, меня привлек факт того, что офис компании также располагался в Берлине и я не нашел ни малейшей причины отказаться от столь соблазнительного предложения. Параллельно с этим “выстрелил” один из откликов оставленных мною лично — тоже из Берлина, но в менее интересной для меня отрасли. Это был мелкий стартап, занимающийся разработкой решений на стыке hard- и software для ускорения работы баз данных. Оглядываясь назад, я особо и не помню почему решил откликнуться на вакансию этой компании — видимо это было в один из тех моментов апатии, когда я был готов пойти работать куда угодно, лишь бы по моей специальности и в Германии.

В своем дальнейшем рассказе я буду называть их просто Компания №1 и Компания №2 для Вашего удобства. Общение с этими компаниями стало для меня еще одним опытом: оно научило меня по-новому смотреть на пресловутый “немецкий орднунг”. Хотя, пожалуй, здесь такая интерпретация не совсем верна, так как редкий берлинский стартап имеет в своем штате хотя бы 60% коренных немцев, и переносить на них блуждающие в сети стереотипы о культуре работы в Германии совсем не стоит.

Первый этап общения с обеими компаниями произошел в 20-х числах июля. Компания №2 сразу призналась мне что поиск Agile Coach в штат для них в новинку и второй этап процесса у них еще не продуман, поэтому это может занять какое-то время. Меня это устраивало, так как жена была со мной на Кипре до начала учебного года в университете и заниматься организацией переезда раньше сентября не сильно то и хотелось.

Август 2017

Каршеринг-сервис (Компания №1) дал положительный фидбэк по первому этапу достаточно быстро и предложил организовать второй звонок — с СТО компании. Стоит отметить, что из всех пройденных мной Skype интервью, первый этап с данной компанией по-прежнему держит пальму первенства по части сумбурности происходящего и отсутствия адекватных вопросов — на тот момент я списал это на качественную “предпродажную подготовку”, проведенную представителями рекрутингового агентства, так сильно хвалившими моё CV и опыт. Звонок с СТО состоялся на следующей неделе, и буквально на следующий день мне был предложен этап, который должен был стать финальным — Skype интервью с СЕО (отсуствие on-site интервью меня тогда не смутило, так как это была всего вторая компания, с которой я зашел так далеко, да и мой работодатель на Кипре выставил мне оффер также по итогу 2 Skype интервью).

СЕО, как и положено руководителю и одному из основателей стартапа в фазе бурного роста, оказался человеком занятым и собеседование несколько раз приходилось переносить, к чему я относился с пониманием. В итоге разговор состоялся: мне было озвучено, что фидбэк от всех 3 коллег, общавшихся со мной ранее, крайне положительный и итоговый результат мне сообщат в течение одной-полутора недель. Тут стоит отметить, что на всем протяжении общения с этой компанией на связи со мной был человек из того самого рекрутингового агентства, который уже не в первый раз работал с этой компанией и старался максимально “накачать” меня полезными знаниями перед каждым из этапов переговоров. В итоге, именно благодаря нему я узнал, что СЕО также попал под действие моих профессиональных чар, однако возникла непредвиденная сложность в виде замаячившей перспективы найма в компанию СРО, контракт с которой должен быть подписан со дня на день и которая также должна будет пообщаться со мной и окончательно утвердить мою кандидатуру. Делать было нечего, компания действительно была мне очень интересна и я согласился подождать. На календаре было 22 августа.

Терпение представителей рекрутингового агентства истекло через 3 недели — устав получать “завтраки” от компании, в итоге пригрозившей агенту отказать мне исключительно из-за его настойчивости, мы по общему согласию решили “отпустить вожжи” и проследить за дальнейшим развитием событий.

Параллельно с этим “проснулась” Компания №2 и пригласила на второй этап к себе в офис. Произошло это за 1 день до моего интервью с СЕО Компании №1, поэтому моим первым ответом была вежливая просьба дать мне неделю на раздумья. Спустя две недели Компания №2 написала мне сама и попросила дать ответ — я согласился, решив что попробовать стоит хотя бы для опыта. Дополнительным фактором была возможность посетить Берлин и успеть заскочить в офис каршеринга, чтобы попытаться прояснить ситуацию с глаза на глаз и постараться склонить-таки чашу весов в мою пользу.

Сентябрь 2017

Состоялась поездка в конце сентября. На мое предложение встретиться лично, CTO каршеринг-сервиса ответил радушным согласием выделить мне “драгоценные 40 минут” времени. В ходе нашей беседы я в очередной раз услышал, что все заинтересованные стороны “поддерживают мою кандидатуру” и все упирается в ту самую злосчастную СРО, которая все никак не подпишет контракт (при этом с момента, когда она впервые стала фигурировать в обсуждениях, прошел уже 1 месяц). Моя инициативность и желание посетить их лично также было “оценено”.

Офис компании произвел позитивное впечатление — спейсы команд имели физические доски, визуализацию артефактов и в целом нормальную продуктивную атмосферу. Впечатление не портил даже продолжавшийся ремонт. Единственное что меня смутило на тот момент — полная укомплектованность имеющихся на данный момент команд, в том числе и специалистами на роль Scrum Master. Однако, CTO заверил меня что перед компанией был поставлен «очень агрессивный план роста” и за наймом новых сотрудников дело не стояло. “Отлично”, — подумал я и поехал готовиться к основному мероприятию поездки.

Вторую половину дня я провел в офисе Компании №2. „Атмосферой стартапа“, опенспейсами и кикером тут и не пахло — в офисе было как-то строго и некомфортно, даже несмотря на пятницу. Средний возраст сотрудников в районе 35 лет и совет директоров, состоящий из серьезных взрослых людей, не очень то вязался с моим представлением о стартапе.

В течение предыдущего года переводом Компании №2 на Agile-рельсы занимались сторонние консультанты. Нанять штатных Scrum Master-ов при их участии не удалось, поэтому они обучили несколько сотрудников компании. В спейсе каждой команды были физические доски, в главном холле располагалась визуализация общего роадмапа компании и всех команд. В дальнейших планах значилось формирование кросс-функциональных команд с участием специалистов как по hard-, так и software и я воспринимал это как серьезный и интересный челлендж.

Само интервью состояло из 4 сеансов общения с двумя-трёмя “будущими коллегами”. Мне задавали различные вопросы, основной целью которых, очевидно, было желание посмотреть как я понимаю Agile, оценить ход моих мыслей и стиль работы. Я не возлагал особых надежд на эту компанию. Возможно, именно поэтому мне удалось вести себя максимально расслабленно и непринужденно. В итоге, именно это и привело к тому, что спустя 5 дней мне поступил оффер.

Каршеринг по-прежнему оставался для меня приоритетным вариантом, поэтому я решил воспользоваться ситуацией, чтобы очередной раз поторопить их, параллельно потянув время на рассмотрение оффера. Помимо вышеперечисленных поводов для сомнения, я также был несколько разочарован предложенной Компанией №2 цифрой, находившейся существенно ниже озвученных мной зарплатных ожиданий (примерно на 20%). Начиная эти поиски, я был готов “потерять” в деньгах при условии социальной значимости продукта и перспектив расширения профессионального кругозора. К сожалению, ни того ни другого эта компания в моих глазах не представляла.

Октябрь 2017

В итоге спустя 5 дней я получил шаблонное письмо с отказом из каршеринг-сервиса. Что послужило тому причиной до сих пор остается для меня тайной — возможно, они так и не нашли поводов брать кого-то на эту позицию прямо сейчас и решили прекратить эту трёхмесячную эпопею. Возможно, проблема была в нежелании платить процент “подогнавшему меня” рекрутинговому агентству. Узнать мне не дано, но вакансия так и висит открытой на сайте компании и регулярно обновляется на профессиональных ресурсах, хотя минуло уже без малого полгода.

Шёл пятый месяц моих поисков. Оставшись “у разбитого корыта” с “работой моей мечты”, я решил выбрать синицу в руках и согласился на оффер Компании №2. Но, как показало время, это было только начало.

Продолжение следует...

Let's block ads! (Why?)

Бот для Starcraft на Rust

StarCraft: Brood War. Как много это значит для меня. И для многих из вас. Настолько много, что я засомневался, давать ли ссылку на вики.

Как-то раз мне в личку постучался Halt и предложил выучить Rust. Как и любые нормальные люди, мы решили начать с hello world написания динамической библиотеки под Windows, которая могла бы загружаться в адресное пространство игры StarCraft и управлять юнитами.

В статье будет описан процесс поиска решений, использования технологий, приемов, которые позволят вам почерпнуть новое в языке Rust и его экосистеме или вдохновиться для реализации бота на своем любимом языке.

Эту статью стоит читать непременно под


Starcraft OST


BWAPI

Этой игре уже 20 лет. И она до сих пор популярна, чемпионаты собирают целые залы людей в США даже в 2017 году, где состоялась битва грандмастеров Jaedong vs Bisu. Помимо живых игроков, в битвах участвуют и бездушные машины! И это возможно благодаря BWAPI. Больше полезных ссылок.

Итак, команда фанатов несколько лет назад отреверсила внутреннести Starcraft и написала на C++ API, которое позволяет писать ботов, внедряться в процесс игры и господствовать над жалкими людишками.

Как это часто бывает, прежде чем построить дом, надо добыть руду, выковать инструменты... написать бота, необходимо реализовать API. Что же может предложить со своей стороны Rust?


FFI

Взаимодействовать с другими языками из Rust довольно просто. Для этого существует FFI. Позвольте мне предоставить краткую выдержку из документации.

Пусть у нас есть библиотека snappy, у которой есть заголовочный файл snappy-c.h, из которого мы будем копировать объявления функций.

Создадим проект с помощью cargo.

$ cargo new --bin snappy
     Created binary (application) `snappy` project
$ cd snappy
snappy$ tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files

Cargo создал стандартную файловую структуру для проекта.

В Cargo.toml укажем зависимость к libc:

[dependencies]
libc = "0.2"

src/main.rs файл будет выглядеть так:

extern crate libc; // Для определения C типов, в нашем случае для size_t
use libc::size_t;

#[link(name = "snappy")] // Указываем имя библиотеки для линковки функции
extern {
    // Пишем руками объявление функции, которую хотим импортировать
    // В C объявление выглядит:
    // size_t snappy_max_compressed_length(size_t source_length);
    fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}

fn main() {
    let x = unsafe { snappy_max_compressed_length(100) };
    println!("max compressed length of a 100 byte buffer: {}", x);
}

Собираем и запускаем:

snappy$ cargo build
...
snappy$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s                                                                                         
     Running `target/debug/snappy`
max compressed length of a 100 byte buffer: 148

Можно вызвать только cargo run, который перед запуском вызывает cargo build. Либо собрать проект и вызвать бинарник напрямую:

snappy$ ./target/debug/snappy 
max compressed length of a 100 byte buffer: 148

Код скомпилируется при условии, что библиотека snappy установлена(для Ubuntu надо поставить пакет libsnappy-dev).

snappy$ ldd target/debug/snappy
    ...
    libsnappy.so.1 => /usr/lib/x86_64-linux-gnu/libsnappy.so.1 (0x00007f8de07cf000)

Как можно увидеть, наш бинарник слинкован с разделяемой библиотекой libsnappy. И вызов snappy_max_compressed_length является вызовом функции из этой библиотеки.


rust-bindgen

Было бы хорошо, если бы мы могли в автоматическом режиме сгенерировать FFI. К счастью, в арсенале растоманов есть такая утилита под названием rust-bindgen. Она умеет генерировать FFI байндинги к C (и некоторым C++) библиотекам.

Установка:

$ cargo install bindgen

Как выглядит использование rust-bindgen? Мы берем заголовочные файлы C/C++, натравливаем на них утилиту bindgen, на выходе получаем сгенерированный Rust код с определениями сишных структур и функций. Вот как выглядит генерация FFI для snappy:

$ bindgen /usr/include/snappy-c.h | grep -C 1 snappy_max_compressed_length
extern "C" {
    pub fn snappy_max_compressed_length(source_length: usize) -> usize;
}

Оказалось, что bindgen пасует перед заголовками BWAPI, генерируя тонны неюзабельных простынок кода (из-за виртуальных функций-членов, std::string в публичном API и т.д.). Все дело в том, что BWAPI написан на C++. C++ вообще сложно использовать даже из C++ проектов. Однажды собранную библиотеку лучше влинковывать тем же линковщиком (одинаковых версий), заголовочные файлы лучше парсить тем же компилятором (одинаковых версий). Потому что существует множество факторов, которые могут повлиять на исход. Например, манглинг, который в GNU GCC до сих пор не могут реализовать без ошибок. Эти факторы настолько значимы, что их не смогли побороть даже в gtest, а в документации указали, что лучше бы вам собирать gtest как часть проекта тем же компилятором и тем же линковщиком.


BWAPI-C

C — это лингва франка программирования. Если rust-bindgen хорошо работает для языка C, почему бы не реализовать BWAPI для C, а потом использовать его API? Хорошая идея!

Да, хорошая идея, пока ты не заглянул в кишки BWAPI и не увидел кол-во классов и методов, которые необходимо реализовать =( Особенно все эти расположения структур в памяти, ассемблеры, патчинг памяти и прочие ужасы, на которые у нас нет времени. Надо по максимуму заиспользовать уже существующее решение.

Но надо как-то бороться с манглингом, C++ кодом, наследованиями и виртуальными функциями-членами.

В C++ есть два мощнейших инструмента, которыми мы воспользуемся для решения нашей задачи, это непрозрачные указатели и extern "C".

extern "C" {} дает возможность C++ коду замаскироваться под C. Это позволяет генерировать чистые имена функций без манглинга.

Непрозрачные указатели дают нам возможность стереть тип и создавать указатель в "какой-то тип", чью реализацию мы не предоставляем. Так как это лишь объявление какого-то типа, а не его реализация, то использовать этот тип по значению невозможно, можно использовать лишь по указателю.

Допустим, у нас есть такой C++ код:

namespace cpp {

struct Foo {
    int bar;

    virtual int get_bar() {
        return this->bar;
    }
};

} // namespace cpp

Мы можем превратить в такой C заголовок:

extern "C" {

typedef struct Foo_ Foo; // Непрозрачный указатель на Foo

// объявляем cpp::Foo::get_bar
int Foo_get_bar(Foo* self);

}

И C++ часть, которая будет связующим звеном между C заголовком и C++ реализацией:

int Foo_get_bar(Foo* self) {
    // кастуем непрозрачный указатель к конкретному cpp::Foo и вызываем метод ::get_bar
    return reinterpret_cast<cpp::Foo*>(self)->get_bar();
}

Не все методы классов пришлось обрабатывать таким образом. В BWAPI есть классы, операции над которыми можно реализовать самому, используя значения полей этих структур, например typedef struct Position { int x; int y; } Position; и методы вроде Position::get_distance.

Были и те, над которыми пришлось постараться особенным образом. Например, AIModule должен быть указателем на C++ класс с определенным набором виртуальных функций-членов. Тем не менее, вот заголовок и реализация.

Итак, спустя несколько месяцев кропотливой работы, 554 метода и десяток классов, на свет родилась кроссплатформенная библиотека BWAPI-C, которая позволяет писать ботов на C. Побочным продуктом стала возможность кросскомпиляции и возможность реализовать API на любом другом языке, который поддерживает FFI и соглашение о вызове cdecl.

Если вы пишите библиотеку, пожалуйста, пишите API на C.


Пишем бота на C

Эта часть описывает общие принципы устройства модулей Starcraft.

Существуют 2 типа ботов: модуль и клиент. Мы рассмотрим пример написания модуля.

Модуль — это загружаемая библиотека, общий принцип загрузки можно посмотреть здесь. Модуль должен экспортировать 2 функции: newAIModule и gameInit.

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

DLLEXPORT void gameInit(void* game) {
    BWAPIC_setGame(game);
}

newAIModule чуть посложнее. Он должен возвращать указатель на C++ класс, у которого существует виртуальная таблица методов с именами onXXXXX, которые вызываются на определенные игровые события. Определим структуру модуля:

typedef struct ExampleAIModule
{
    const AIModule_vtable* vtable_;

    const char* name;
} ExampleAIModule;

Первым полем обязательно должен быть указатель на таблицу методов (магия, все дела). Итак, функция newAIModule:

DLLEXPORT void* newAIModule() {
    ExampleAIModule* const module = (ExampleAIModule*) malloc( sizeof(ExampleAIModule) );
    module->name = "ExampleAIModule";
    module->vtable_ = &module_vtable;

    return createAIModuleWrapper( (AIModule*) module );
}

createAIModuleWrapper — это еще одна магия, которая превращает С указатель в указатель на С++ класс с виртуальными методами функциями-членами.

module_vtable — это статическая переменная на таблицу методов, значения методов заполнены указателями на глобальные функции:

static AIModule_vtable module_vtable = {
    onStart,
    onEnd,
    onFrame,
    onSendText,
    onReceiveText,
    onPlayerLeft,
    onNukeDetect,
    onUnitDiscover,
    onUnitEvade,
    onUnitShow,
    onUnitHide,
    onUnitCreate,
    onUnitDestroy,
    onUnitMorph,
    onUnitRenegade,
    onSaveGame,
    onUnitComplete
};

void onEnd(AIModule* module, bool isWinner) { }
void onFrame(AIModule* module) {}
void onSendText(AIModule* module, const char* text) {}
void onReceiveText(AIModule* module, Player* player, const char* text) {}
void onPlayerLeft(AIModule* module, Player* player) {}
void onNukeDetect(AIModule* module, Position target) {}
void onUnitDiscover(AIModule* module, Unit* unit) {}
void onUnitEvade(AIModule* module, Unit* unit) {}
void onUnitShow(AIModule* module, Unit* unit) {}
void onUnitHide(AIModule* module, Unit* unit) {}
void onUnitCreate(AIModule* module, Unit* unit) {}
void onUnitDestroy(AIModule* module, Unit* unit) {}
void onUnitMorph(AIModule* module, Unit* unit) {}
void onUnitRenegade(AIModule* module, Unit* unit) {}
void onSaveGame(AIModule* module, const char* gameName) {}
void onUnitComplete(AIModule* module, Unit* unit) {}

По названию функций и их сигнатур понятно, при каких условиях и с какими аргументами они вызываются. Для примера я все функции сделал пустыми, кроме

void onStart(AIModule* module) {
    ExampleAIModule* self = (ExampleAIModule*) module;
    Game* game = BWAPIC_getGame();
    Game_sendText(game, "Hello from bwapi-c!");
    Game_sendText(game, "My name is %s", self->name);
}

Данная функция вызывается при старте игры. В качестве аргумента передается указатель на текущий модуль. BWAPIC_getGame возвращает глобальный указатель на игру, который мы установили с помощью вызова BWAPIC_setGame. Итак, покажем пример кросскомпиляции и работы модуля:

bwapi-c/example$ tree
.
├── BWAPIC.dll
└── Dll.c

0 directories, 2 files

bwapi-c/example$ i686-w64-mingw32-gcc -mabi=ms -shared -o Dll.dll Dll.c -I../include -L. -lBWAPIC
bwapi-c/example$ cp Dll.dll ~/Starcraft/bwapi-data/
bwapi-c/example$ cd ~/Starcraft/bwapi-data/
Starcraft$ wine bwheadless.exe -e StarCraft.exe -l bwapi-data/BWAPI.dll --headful
...
...
...

Тыкаем в кнопочки и запускаем игру. Подробнее про запуск можно прочитать на сайте BWAPI и в BWAPI-C.

Результат работы модуля:

image

Чуть более сложный пример модуля, который показывает работу с итераторами, управлением юнитов, поиском минералов, выводом статистики можно найти в bwapi-c/example/Dll.c.


bwapi-sys

В экосистеме Раста принято определенным образом называть пакеты, которые линкуются к нативным библиотекам. Любой пакет foo-sys занимается двумя важными функциями:


  • Линкуется к нативной библиотеке libfoo
  • Предоставляет объявления к функциям из библиотеки libfoo. Но только лишь объявления, высокоуровневые абстракции в *-sys крейтах не предоставляются.

Чтобы *-sys пакет умел успешно линковаться, в него встраивают поиск нативной библиотеки и/или сборку библиотеки из исходников.

Чтобы *-sys пакет предоставил объявления, надо или написать их руками, или сгенерировать с помощью bindgen. Снова bindgen. Попытка номер два =)

Генерация байндингов с помощью bwapi-c становится до неприличия простой:

bindgen BWAPI.h -o lib.rs \
  --opaque-type ".+_" \
  --blacklist-type "std.*|__.+|.+_$|Game_v(Send|Print|Draw).*|va_list|.+_t$" \
  --no-layout-tests \
  --no-derive-debug \
  --raw-line "#![allow(improper_ctypes, non_snake_case)]" \
  -- -I../submodules/bwapi-c/include

sed -i -r -- 's/.+\s+(.+)_;/pub struct \1;/' lib.rs

Где BWAPI.h — файл с инклудами всех сишных заголовков из BWAPI-C.

Например, для уже известных функций bindgen сгенерировал такие объявления:

extern "C" {
    /// BWAPIC_setGame must be called from gameInit to initialize BWAPI::BroodwarPtr
    pub fn BWAPIC_setGame(game: *mut Game);
}
extern "C" {
    pub fn BWAPIC_getGame() -> *mut Game;
}

Существуют 2 стратегии: хранение сгенерированного кода в репозитории и генерация кода на лету при сборке. И тот и другой подход имеет свои преимущества и недостатки.

Приветствуем bwapi-sys, еще одну маленькую ступень к нашей цели.

Помните, я говорил про кроссплатформенность? К проекту присоединился nlinker и реализовал хитрую стратегию. Если целевой таргет — Windows, то скачиваем уже собранную BWAPIC из гитхаба. А для остальных таргетов собираем BWAPI-C из исходников для OpenBW (расскажу чуть позже).


bwapi-rs

Теперь, когда у нас есть байндинги, мы можем описывать высокоуровневые абстракции. У нас есть 2 типа, с которыми надо работать: чистые значения и непрозрачные указатели.

С чистыми значениями все проще. Возьмем за пример цвета. Нам надо добиться удобного использования из Rust кода, чтобы можно было использовать цвета удобным и естественным образом:

game.draw_line(CoordinateType::Screen, (10, 20), (30, 40), Color::Red);
                                                                  ^^^

Значит для удобного использования надо будет определить идиоматическое для языка Rust перечисление с константами из C++ и определить методы конвертирования в bwapi_sys::Color с помощью типажа std::convert::From:

// FFI version
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Color {
    pub color: ::std::os::raw::c_int,
}

// Idiomatic version
#[derive(PartialEq, PartialOrd, Copy, Clone)]
pub enum Color {
    Black = 0,
    Brown = 19,
...

Хотя для удобства можно воспользоваться крейтом enum-primitive-derive.

С непрозрачными указателями ничуть не сложнее. Для этого воспользуемся паттерном Newtype:

pub struct Player(*mut sys::Player);

То есть Player — это некая структура с приватным полем — сырым непрозрачным указателем из C. И вот как можно описать метод Player::color:

impl Player {

    // так объявлен метод Player::getColor в bwapi-sys
    //extern "C" {
    //    pub fn Player_getColor(self_: *mut Player) -> Color;
    //}

    pub fn color(&self) -> Color {
        // bwapi_sys::Player_getColor - обертка функции из BWAPI-C 
        // self.0 - сырой указатель
        let color = unsafe { bwapi_sys::Player_getColor(self.0) };
        color.into() // каст bwapi_sys::Color -> Color
    }
}

Теперь мы можем написать своего первого бота на Rust!


Пишем бота на Rust

В качестве proof of concept бот будет похож на одну известную страну: весь его функционал будет заключаться в найме рабочих и сборе минералов.

North Korea

South Korea

Начнем с обязательных функций gameInit и newAIModule:

#[no_mangle]
pub unsafe extern "C" fn gameInit(game: *mut void) {
    bwapi_sys::BWAPIC_setGame(game as *mut bwapi_sys::Game);
}

#[no_mangle]
pub unsafe extern "C" fn newAIModule() -> *mut void {
    let module = ExampleAIModule { name: String::from("ExampleAIModule") };
    let result = wrap_handler(Box::new(module));

    result
}

#[no_mangle] выполняет ту же функцию, что и extern "C" в C++. Внутри wrap_handler происходит всякая магия с подстановкой таблицы виртуальных функций и маскировкой под C++ класс.

Описание структуры модуля еще проще и красивее, чем в C:

struct ExampleAIModule {
    name: String,
}

Добавим пару методов для отрисовки статистики и раздачи приказов:

impl ExampleAIModule {
    fn draw_stat(&mut self) {
        let game = Game::get();
        let message = format!("Frame {}", game.frame_count());
        game.draw_text(CoordinateType::Screen, (10, 10), &message);
    }
    fn give_orders(&mut self) {
        let player = Game::get().self_player();

        for unit in player.units() {

            match unit.get_type() {
                UnitType::Terran_SCV |
                UnitType::Zerg_Drone |
                UnitType::Protoss_Probe => {
                    if !unit.is_idle() {
                        continue;
                    }

                    if unit.is_carrying_gas() || unit.is_carrying_minerals() {
                        unit.return_cargo(false);
                        continue;
                    }

                    if let Some(mineral) = Game::get()
                        .minerals()
                        .min_by_key(|m| unit.distance_to(m))
                    {
                        // WE REQUIRE MORE MINERALS
                        unit.right_click(&mineral, false);
                    }
                }

                UnitType::Terran_Command_Center => {
                    unit.train(UnitType::Terran_SCV);
                }

                UnitType::Protoss_Nexus => {
                    unit.train(UnitType::Protoss_Probe);
                }

                UnitType::Zerg_Hatchery |
                UnitType::Zerg_Lair |
                UnitType::Zerg_Hive => {
                    unit.train(UnitType::Zerg_Drone);
                }

                _ => {}
            };
        }
    }
}

Чтобы тип ExampleAIModule превратился в настоящий модуль, необходимо научить его отзываться на события onXXXX, для чего надо реализовать типаж EventHandler, который является аналогом виртуальной таблицы AIModule_vtable из C:

impl EventHandler for ExampleAIModule {
    fn on_start(&mut self) {
        Game::get().send_text(&format!("Hello from Rust! My name is {}", self.name));
    }
    fn on_end(&mut self, _is_winner: bool) {}
    fn on_frame(&mut self) {
        self.draw_stat();
        self.give_orders();
    }
    fn on_send_text(&mut self, _text: &str) {}
    fn on_receive_text(&mut self, _player: &mut Player, _text: &str) {}
    fn on_player_left(&mut self, _player: &mut Player) {}
    fn on_nuke_detect(&mut self, _target: Position) {}
    fn on_unit_discover(&mut self, _unit: &mut Unit) {}
    fn on_unit_evade(&mut self, _unit: &mut Unit) {}
    fn on_unit_show(&mut self, _unit: &mut Unit) {}
    fn on_unit_hide(&mut self, _unit: &mut Unit) {}
    fn on_unit_create(&mut self, _unit: &mut Unit) {}
    fn on_unit_destroy(&mut self, _unit: &mut Unit) {}
    fn on_unit_morph(&mut self, _unit: &mut Unit) {}
    fn on_unit_renegade(&mut self, _unit: &mut Unit) {}
    fn on_save_game(&mut self, _game_name: &str) {}
    fn on_unit_complete(&mut self, _unit: &mut Unit) {}
}

Сборка и запуск модуля так же просты, как и для C:

bwapi-rs$ cargo build --example dll --target=i686-pc-windows-gnu                                                                   
bwapi-rs$ cp ./target/i686-pc-windows-gnu/debug/examples/dll.dll ~/Starcraft/bwapi-data/Dll.dll
bwapi-rs$ cd ~/Starcraft/bwapi-data/
Starcraft$ wine bwheadless.exe -e StarCraft.exe -l bwapi-data/BWAPI.dll --headful
...
...
...

И видео работы:



OpenBW

Эти ребята пошли еще дальше. Они решили написать open-source версию игры SC:BW! И у них неплохо получается. Одной из их целей была реализация HD картинки, но SC: Remastered их опередили =( На данный момент можно использовать их API для написания ботов (да, тоже на C++). Но самой умопомрачительной фичей является возможность просматривать реплеи прямо в браузере.


Заключение

При реализации осталась нерешенная проблема: мы не контролируем уникальность ссылок, а одновременное существование &mut и & при изменении объекта приведет к неопределенному поведению. Беда. Но для решения этой задачи придется качественно перелопатить C++ API и правильно проставить const квалификаторы.

Мне очень понравилось работать над этим проектом, я 하루종일 смотрел реплеи и глубоко погрузился в атмосферу. Эта игра оставила 믿어지지 않을 정도인 наследие. Ни одну игру нельзя 비교할 수 없다 по популярности с SC:BW, а ее влияние на 대한민국 정치에게 оказалось немыслимым. Прогеймеры в Корее 아마도 так же популярны, как и 드라마 주연 배우들 корейских дорам, транслирующихся в прайм-тайм. 또한, 한국에서 프로게이머라면 군대의 특별한 육군에 입대할 수 있다.

Да здравствует StarCraft!


Ссылки

bwapi-rs — https://github.com/RnDome/bwapi-rs
bwapi-sys — https://github.com/RnDome/bwapi-sys
bwapi-c — https://github.com/RnDome/bwapi-c
bwapi — https://github.com/bwapi/bwapi/
openbw — http://openbw.com/

Let's block ads! (Why?)

[Перевод] Зонд NASA «коснётся» Солнца — и не расплавится


Источник:NASA Goddard/YouTube
Это абсолютно потрясно!

Буквально через несколько недель NASA собирается запустить в космос одну из своих самых амбициозных миссий. Солнечный зонд Parker совершит несколько «нырков» к поверхности Солнца, чтобы практически «коснуться» его, и окажется таким образом настолько близко к нашей звезде, чем кто-либо до этого.
Три самых низких орбиты Parker проходят на высоте порядка 6,1 миллиона километров над поверхностью, внутри солнечной короны, где температуры достигают нескольких миллионов градусов Цельсия.
Понятное дело, что понадобится защита, и она есть, довольно хитро устроенная. Но к этому мы вернёмся несколько позже, а пока что — поговорим об обжигающей жаре.

Сложно представить, как вообще можно уберечься в подобных условиях — ведь температура всего лишь в 460 градусов Цельсия на Венере быстро приводила к отказу электронного оборудования на советских АМС в восьмидесятые годы.

Но NASA объясняет нам, что есть нюанс между фактической температурой объекта и тепловым излучением, поскольку это сильно влияет на передачу тепла в пространстве. Температура характеризует то, какой скоростью — и соответственно, энергией — обладает частица, а тепловое излучение — сколько энергии она фактически переносит. В космосе частицы могут двигаться с высокой скоростью, но передавать не так много энергии, поскольку их не так уж много.

«Parker неоднократно пройдёт через солнечную корону, которая несмотря на свою высокую температуру имеет довольно низкую плотность», — говорит Сьюзан Дарлинг — «Это довольно просто представить на примере духовки и кастрюльки с кипящей водой — в духовке вы сможете продержать руку значительно дольше, потому что воздух имеет меньшую плотность, чем вода. Соответственно, в сравнении с непосредственно поверхностью Солнца, в короне зонд столкнётся с меньшим количеством частиц и слабее нагреется».

Что это означает, применительно к тепловой защите? То, что она должна будет выдержать температуру около 1370 градусов Цельсия, чтобы уберечь содержимое.

Добиться этого можно лишь при помощи удивительных технологий. Щит зонда представляет собой своеобразный «сэндвич» из двух перезакалённых углерод-углеродных композитных пластин, между которыми 11,5 сантиметров углеродной пены, диаметром 2,4 метра и общим весом всего 72,5 килограмма. Сторона, устремлённая к Солнцу, выкрашена в белый цвет краской на основе керамики с целью отражения максимального количества теплового излучения.

И что поразительно — температура за щитом будет всего 30 градусов Цельсия.

Все инструменты, которые будут находиться вне защищаемой зоны, изготовлены из тугоплавких материалов. Например, цилиндр Фарадея, при помощи которого аппарат будет определять заряд и интенсивность солнечного ветра, сделан из титаноциркономолибденового сплава, (температура плавления около 2350 градусов Цельсия), электростатические пластины — из вольфрама (3422 градуса), а вся проводка будет изготовлена из ниобия (2477 градусов).

Разумеется, Parker будет поддерживать ориентацию в пространстве таким образом, чтобы более деликатное оборудование не попало под удар испепеляющих солнечных лучей, а солнечные панели будут убраны за щит во избежание перегрева на слишком «горячих» участках траектории. Дополнительно зонд оснащён системой жидкостного охлаждения на деионизированной воде.

Несомненно, в «начинке» аппарата очень много и других неординарных инженерных решений. Что ж, ждём не дождёмся, какие новые данные нам принесёт Parker о Солнце, его сумасшедшей атмосфере и бешеных «ветрах».

Let's block ads! (Why?)

План ICANN: в корпорации предложили новую модель управления корневыми серверами DNS

Консультационный совет ICANN по управлению корневыми серверами RSSAC предложил новую модель управления корневой зоной DNS. Она предусматривает уменьшение числа активных КС и внедрение пяти новых ответственных структур. Подробнее о модели рассказываем под катом.


/ фото Oliver Dean CC

Как управляется система корневых DNS-серверов


Уже долгое время система состоит из 13 корневых серверов, которыми управляют 12 компаний на основании соглашений с ICANN. Среди этих организаций есть как независимые, так и государственные. Все решения касательно работы КС эти компании принимают самостоятельно. Наглядный пример того, как проходит координация работы системы корневых серверов, можно посмотреть в статье CTO интернет-регистратора RIPE NCC Андрея Робачевского.

По этой схеме все стабильно функционирует долгие годы. Однако в RSSAC хотят сделать работу корневых DNS-серверов более «прозрачной» и организованной.

В чем суть предложения RSSAC


Представители RSSAC говорят, что они долгое время анализировали работу операторов корневых серверов. И пришли к выводу, что действия операторов, по сути, бесконтрольны и основаны на доверии. Потому они предложили внедрить новую модель, обеспечивающую, по их мнению, большую прозрачность и безопасность.

Главная идея состоит в том, чтобы создать единую структуру из пяти функциональных подразделений для управления всем, что связано с КС:

  1. Секретариат (Secretariat Function – SF). Это подразделение — подобие интерфейса, который связывает операторов корневых серверов и интернет-сообщество. Оно будет выступать своеобразной платформой для обсуждения технических вопросов и решения административных задач.
  2. Подразделение стратегии, архитектуры и политик (Strategy, Architecture, and Policy Function – SAPF). Здесь будут следить за работой корневых DNS-серверов, предлагать планы по внедрению новых элементов архитектуры для усиления безопасности, производительности и масштабируемости глобальной системы.
  3. Подразделение делегирования полномочий (Designation and Removal Function – DRF). Будет проводить аудиты и давать рекомендации по назначению операторов КС и прекращению их полномочий.
  4. Подразделение мониторинга и оценки производительности операторов (Performance Monitoring and Measurement Function – PMMF). Эта структура будет собирать метрики и технические данные о том, насколько продуктивно работает каждый оператор и система в целом.
  5. Финансовое подразделение (Financial Function – FF). Здесь будет регулироваться финансовая составляющая работы всей системы. Авторы плана предлагают создать фонд, с помощью которого заинтересованные стороны смогут распределять средства на проведение исследований и урегулирование чрезвычайных ситуаций, связанных с работой корневых DNS-серверов.

Вот так выглядит новая схема работы системы по задумке RSSAC:

Во время презентации модели представители RSSAC Трипти Синха (Tripti Sinha) и Брэд Верд (Brad Verd) отметили, что ее реализация позволит уменьшить число корневых DNS-серверов – некоторые из них будут объединены (но какие и сколько, пока неизвестно). Однако насколько КС станет меньше, спикеры не уточнили. По их мнению, уменьшение числа корневых DNS-серверов поможет улучшить качество предоставляемых услуг и контроль за ними.

Мнения сообщества


Один из резидентов The Register в своем комментарии на площадке выразил сомнения насчет правильности идеи объединения корневых DNS-серверов. По его мнению, так хакерам станет проще проводить атаки, так как консолидация упростит процедуру выбора цели для взлома.

Некоторые вспомнили недавнюю ситуацию с WHOIS, когда ICANN несколько раз пытались привести работу сервиса в соответствии с GDPR и встретили сопротивление со стороны сообщества и регистраторов, поскольку не смогли до конца продумать план реализации идеи. Из-за этой истории пользователи заявили, что передавать контроль над корневыми DNS-серверами в руки ICANN — не лучшее решение.

Однако были и те, кто посчитал, что идея в целом неплохая, так как более четкая структура управления должна ускорить разрешение проблем безопасности.

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



P.S. Дополнительные материалы из Первого блога о корпоративном IaaS:
P.P.S. Еще пара статей из нашего блога на Хабре:

Let's block ads! (Why?)

Кунсткамера: Е-метр — саентологический прибор для измерения «тэтанов»

image

В наше время много странных организаций. Одна из них — сообщество саентологов. Их учение представляет собой смесь весьма специфической религии и околонаучной ереси философии. Основные нюансы саентологии и теоретическая платформа, на которой зиждется учение были неплохо показаны в мультсериале South Park, сезон 9, серия 12, так что в этом посте не будет подробных вводных.

Но раз уж пост такого рода появился на Хабре, то он должен иметь определенное отношение к этому ресурсу. И оно есть — в этом материале рассказывается о том, что такое Е-метр. Гаджет используется саентологами для того, чтобы определить концентрацию тэтанов (даже не спрашивайте, что это). Стоит он около 7 тысяч евро. Вероятно, в его конструкции используются рубины и бриллианты? Ничуть не бывало. Давайте посмотрим, что он собой представляет.

История создания


Впервые о E-метре стало известно в 40-х годах прошлого века. Его создал изобретатель и мануальный терапевт из США Волней Мэтисон. Изначально прибор назывался Mathison Model B Electropsychometer — «электропсихометр Мэтисона модель Б. Мэтисон». Сам Мэтисон был психоаналитиком, приверженцем школы Фрейда.

Для того, чтобы воспользоваться психрометром, пациент должен был положить руки на электроды (изначально ими служили обычные металлические терки). Эта система измеряла сопротивление тела человека, а Мэтисон, глядя на результат, делал определенные выводы относительно психического состояния своего клиента.

Уже через десять лет эту систему стали активно использовать в своих интересах саентологи. Е-метр в несколько измененном виде используется и по сей день. Причем после того, как к его конструкции приложил руку Рон Хаббард (основатель саентологии), психометр стал называться «Электрометром Хаббарда». Основатель саентологии даже смог получить на него патент — это случилось в 1966 году. В патенте идет вполне логичное описание психометра в качестве системы для измерения электрического сопротивления тела человека, никакие тэтаны в тексте не упоминаются. Есть и патент на дизайн устройства.

По мнению саентологов, аппарат позволяет оценить предрасположенность потенциального адепта к самой саентологии. Чем выше полученный результат — тем лучше. Выводы о пригодности потенциального члена организации к несению своего тяжкого бремени делаются путем анализа такой составляющей, как тэтан (что это такое — лучше гуглить, объяснять понятие можно, если сам понимаешь, что это такое, я лично не очень понял).

Что на самом деле представляет собой Е-метр?


Это обычный гальванометр на основе моста Уитстона. То есть устройство измеряет электрическую проводимость тела через кожные покровы ладоней рук. Никакой магии — обычные фокусы.

По мнению экспертов, Е-метр не может отличать положительные эмоции от отрицательных, он умеет регистрировать лишь такой параметр, как возбуждение. Стоит отметить, что детекторы лжи, которые зачастую сильно ругают за их некачественную работу, регистрируют от 4 до 9 параметра тела человека. А вот Е-метр, как уже указывалось выше — всего один параметр.

Снятие этого одного параметра очень сильно зависит от большого количества самых разных факторов. Например:

  • Характеристики микроклимата в месте проведения анализа (температура, влажность и давление воздуха);
  • Площадь соприкосновения ладоней с датчиками;
  • Тонус мышц на момент снятия показаний;
  • Влажность кожи;
  • Число астероидов в поясе астероидов;
  • Чистота рук;
  • Настроение и вообще психологическое состояние человека.

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

Разбираем Е-метр на запчасти и оцениваем его общую стоимость


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

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

Сам прибор соответствует стандартам измерительных устройств 90-х годов прошлого века. Самая сложная деталь в конструкции — 8051-й микроконтроллер. Да, есть здесь и цифровой циферблатик, который тоже что-то показывает.

Что касается стоимости отдельных узлов, она невысокая. Так потенциометр, установленный в Е-метре, стоит от $20 до $60. Выключатель — еще $5. Корпус — пускай $20. Совокупная стоимость всех элементов вряд ли превышает $100-$150. Напомню, цена прибора составляет около семи тысяч евро.

Вот качество сборки всего этого — на высоте, здесь саентологи постарались. Создатели прибора постарались, люфтов и зазоров нет. Ничего не скрипит, сборка отличная. Более подробный разбор полетов — ниже.


Вывод? А его здесь нет, каждый может сделать его для себя сам. Одно понятно — людей обманывали и будут обманывать самыми изощренными способами, привлекая околонаучные методы воздействия на неокрепшее сознание потенциальных адептов. Повлияет ли обзор Е-метра на сторонников саентологии? Вряд ли.

Let's block ads! (Why?)

«Чтение на выходные»: 25 материалов для начинающих любителей винила

Сегодня мы подобрали материалы из «Мира Hi-Fi» специально для начинающих и всех, кто хотел бы познакомиться с экосистемой винила, подобрать проигрыватель и разобраться с настройкой.


Фото Best Picko / CC

Выбор проигрывателя


  • Назад к винилу — вперед к настоящему звуку. Статья о том, как не потратить на проигрыватель безумную сумму и получить хорошее качество звука. Расскажем, когда стоит доплатить за звук и взять «вертушку» подороже, а в каком — остановить свой выбор на подержанном аппарате.

  • В трех соснах. Выбираем проигрыватель виниловых пластинок. Руководство по выбору проигрывателя в зависимости от вашей степени «знакомства» с винилом. Готовы тратить большие деньги на качественные пластинки или просто хотите послушать винил, доставшийся по наследству? Рассматриваем три ситуации и даем конкретные рекомендации для энтузиастов, скептиков и тех, «кто уходил, но обещал вернуться».

  • Всё о виниле: выбор проигрывателя на любой бюджет. Обзор виниловых проигрывателей стоимостью от 24 до нескольких сотен тысяч рублей. Тестируем проигрыватели в деле и рассказываем, для воспроизведения каких музыкальных стилей они подойдут лучше всего.

  • Проигрыватели виниловых дисков: обзор. Сравнение четырех проигрывателей в ценовой категории от 100 до 150 тысяч рублей. Оцениваем простоту настройки и установки и их рабочие характеристики (в цифрах). В конкурсе участвуют: Clearaudio Concept, Pro-Ject 2-Xperience 2-Pack, Rega RP6 и Thorens TD 206.

Устройство проигрывателя: аксессуары и комплектующие


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

  • Типы приводов: особенности и сложности. Что является основной частью системы, вращающей пластинку? Привод. Разбираемся в теории и особенностях прямого и пассикового приводов и их влиянии на звук. Также попробуем разрешить споры о том, что же лучше: прямой привод с кварцем или без оного.

  • 10 правил выбора головки звукоснимателя. Руководство для желающих приобрести новый картридж — пошаговый гид по всем компонентам головок звукоснимателя: от материала и профиля заточки до взаимодействия с другими элементами «вертушки».

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

  • Как поменять звукосниматель. Выбрали и купили звукосниматель, теперь его нужно установить. В этом нет ничего сложного, главное делать все плавно и без сильного нажима. Приводим подробную инструкцию.

Настройка проигрывателя


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

  • Настраиваем проигрыватель виниловых дисков. Статья посвящена основным этапам настройки аналоговых «вертушек». Куда ставить устройство, как регулировать звукосниматель и уровень тонарма и почему важно правильно выставить прижимную силу картриджа.

  • Помощники в настройке винилового проигрывателя. Клемпы, тестовые пластинки, конверты, маты и шаблоны – все, что поможет вам добиться лучшего звучания проигрывателя и сохранить пластинки в целости. Рассказываем, как выбрать наиболее качественные и удобные аксессуары, подходящие под ваши нужды.


Фото Ryan Atkins / CC
  • Советы от A.J. Van Den Hul: как установить и настроить проигрыватель грампластинок. Создатель бренда звукоснимателей и кабелей Van Den Hul рассказывает, как улучшить звучание проигрывателя, не вкладывая в него дополнительные деньги. Но придется повозиться с его настройкой: подкрутить прижимную силу, настроить вертикальный угол VTA и азимут. Статья предлагает практические рекомендации на этот счет.

  • Компендиум, или краткое руководство по High End-аудио. Ещё один взгляд на то, как нужно настраивать тонарм, звукосниматель и привод проигрывателя. Отдельно в статье рассматривается вопрос контроля «вредности» резонансов. Это своеобразное руководство о том, как на выходе получить качественную музыку, а не «музыкальные консервы».

Хаки по уходу за проигрывателем и пластинками


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

Разное о виниле и проигрывателях


  • Винил: новое — это хорошо забытое старое. Индустрия винила переживает «второе рождение», по крайней мере, так говорят критики. Разбираемся в причинах роста популярности этого носителя и какую роль в этом сыграли молодежные субкультуры и кинематограф.

  • Винил умер, да здравствует винил. К чему следует быть готовым начинающему любителю винила? И как понять, стоит ли это увлечение ваших времени и денег? На эти вопросы отвечает эксперт в области звука Керим Татевян. Он также расскажет, как выбрать пластинку, как за ней ухаживать и, главное, как её правильно слушать.

  • Виброизоляция от Music Hall: логика и увлечение. Рассматриваем технические особенности аппаратуры от Music Hall, «разглядываем» столы и тонармы и даем полезные советы владельцам, желающим усовершенствовать свой проигрыватель.



Дополнительное чтение – материалы по теме из нашей Академии Винила:

Let's block ads! (Why?)

[Перевод] Что случилось, когда мы взломали выставку?

QRCODE через мобильное приложение для сканирования бейджей участников выставки проектов по информационной безопасности.
В прошлом году мы посетили большую выставку проектов по информационной безопасности в Лондоне. В ходе подготовки нам прислали наши пропуска в виде PDF-ников «распечатай сам».
Toms exhibitor badge

Мы сразу обратили внимание на два вида штрихкода. Что интересно, QR-код выглядел слишком плотным, учитывая, что в нём достаточно хранить только ID участника. Будучи любознательными по своей природе, мы запустили QR-сканер и получили содержимое кода:
{"CJe";"BHEEZST","DO";"Cvmmfuqsppg","G";"upn","KU";"Qfofusbujpo uftufs","T";"xzbuu"}

Это оказался «почти-но-не-совсем-JSON». Одним из плюсов такого короткого имени, как у меня, является то, что оно бросается в глаза в подобных ситуациях. Поэтому я сразу заметил, что моё имя закодировано в ROT-25 («tom» превратилось в «upn»). Он также известен как Шифр Цезаря, где каждая буква заменена на другую с фиксированным смещением (в данном случае вместо каждой буквы использовалась соседняя в алфавите). Прогнав строку через декодер (с учётом разметки JSON), мы получили:
{"BId";"AGDDYRS","CN";"Bulletproof","F";"tom","JT";"Penetration tester","S";"wyatt"}

Это уже более читаемо.

Сломаем?


Любопытно, что QR-код хранит информацию, похоже, связанную с полем «BId» в базе данных. С чего бы? Что ж, это довольно просто. Организаторы сделали мобильное приложение для вендоров, которое помогает им собирать контакты участников в ходе выставки. Мы предположили, что данные забиты в QR-код на тот случай, когда Wi-Fi или сотовый сигнал неустойчивы.

Пока мы мало что можем сделать с этой информацией, кроме как поменять наши данные, чтобы избежать спама от вендоров с мероприятия. Это было бы забавно, но врядли достойно емейла разработчику системы. Итак, мы отправились в Play Market и установили соответствующее приложение, чтобы посмотреть, что оно делает.

Screenshot of the app

И тут мы столкнулись с проблемой: у нас не было необходимых данных от организаторов мероприятия. Мы подумали, что могли бы подделать ответ сервера с помощью MiTM proxy, и приложение пустит нас. Мы настроили Burpsuite и записали несколько неудачных попыток входа, надеясь перехватить трафик и поиграться с ним.

Увы, у нас не получилось. Приложение направляло все запросы с помощью SOAP, а ответы были неочевидны. Впрочем, сервер публикует WSDL документы для приложения.

Это не конец


Почему бы не написать поддельный веб-сервис, чтобы больше не обращаться к настоящему серверу приложения? Через несколько часов у нас был такой сервис, и весь трафик был завёрнут на него. Работает! Приложение аутентифицировалось с любыми данными и подключалось к фейковому мероприятию.
Fake show in app

Мы отсканировали пару бейджей, и, похоже, всё работало правильно. Прогресс! После блуждания по приложению некоторое время стало очевидно, что оно использует какой-то фреймворк на основе WebView. Немного поковырявшись в APK, мы нашли ряд упоминаний Sencha и Ext.js, что подтвердило наше предположение.

А теперь — самое интересное. Если приложение состоит из обычной смеси HTML и JavaScript, может ли оно быть уязвимым для стандартных веб-атак? Мы завернули несколько XSS'ок в «не-совсем-JSON», который ожидает приложение, отсканировали их, и…

Fake ID in app

Мы сломали его


Превосходно! HTML-инъекция в поле «JT» показала изображение. Мы можем добавить атрибут «onerror» в этот тэг, чтбы добиться выполнения скрипта, но упираемся в ограничение максимальной длины QR-кода. В итоге мы создали полезную нагрузку, которая скачивала JS-файл с сервера и запускала его на устройстве. Вот, например, стандартный тест на «alert()»:
coding an alert

Сканирование штрихкода вызывает срабатывание XSS и исполнение кода:
Showing an XSS flaw

Мы ужали это так, чтобы оно аккуратно умещалось в максимальный размер читаемого QR-кода, не слишком плотного для печати на пропуске. После чтения документации на API Ext.js и сопоставления её с декомпилированным кодом APK нам удалось сделать штрихкод, который:
  1. Скачивает JS-файл с удалённого сервера
  2. Считывает сессионные ключи со смартфона и отправляет их на наш сервер
  3. Считывает содержимое закэшированной базы данных контактов из приложения, включающей имена и адреса электронной почты всех, чьи пропуска были отсканированы данным устройством
  4. Удаляет свою запись со смартфона

Затем атака сводится к следующему: вендор сканирует мой QR-код в обмен на бесплатную ручку, а я получаю полный список всех контактов, отсканированных этим устройством.

Полезная нагрузка:

Showing the Payload

Запросы к веб-серверу:

Showing the server response

Всё хорошо, что хорошо кончается


Мы обратили на это внимание вендоров на выставке, и после некоторого обсуждения они решили не использовать приложение в этом году. Всего несколько человек на мероприятии воспользовались приложением, в то время как большинство предпочли ему простые небольшие сканеры штрихкодов. Приложение из Маркета скачали всего около 500 раз. Тем не менее, это интересный вектор для XSS, который показывает, что вам действительно нужно фильтровать данные перед использованием независимо от их источника.

Хотя это конкретное приложение не использовалось широко, представьте, если бы уязвимость была в приложении, котором пользуются тысячи или скачивают миллионы? Все эти данные достались бы злоумышленникам, которые бы распорядились ими на своё усмотрение: от фишинговых кампаний до брутфорс-атак.

Let's block ads! (Why?)

[Перевод] Оптимизация рендеринга сцены из диснеевского мультфильма «Моана». Часть 2

image

Вдохновлённый первой победой при парсинге с помощью описания сцены острова из мультфильма «Моана» компании Disney, я далее углубился в изучение использования памяти. Можно было сделать ещё очень многое со временем выполнения, но я решил, что будет полезно сначала разведать обстановку.

Исследование времени выполнения я начал со встроенной статистики pbrt; в pbrt есть ручная настройка значительных выделений памяти для отслеживания использования памяти, а после завершения рендеринга выводится отчёт о выделении памяти. Вот, каким изначально был отчёт о выделении памяти для этой сцены:

Память
BVH-дерево 9,01 ГиБ
Кривые 1,44 ГиБ
MIP-текстуры 2,00 ГиБ
Меши треугольников 11,02 ГиБ

Что касается времени выполнения, то встроенная статистика оказалась краткой и выдала отчёт только о выделении памяти под известные объекты размером в 24 ГБ. top сообщил, что на самом деле использовано около 70 ГБ памяти, то есть в статистике не учтено 45 ГБ. Небольшие отклонения вполне объяснимы: распределителям динамической памяти требуется дополнительное место для регистрации использования ресурсов, часть теряется из-за фрагментации, и так далее. Но 45 ГБ? Здесь определённо скрывается что-то нехорошее.
Чтобы понять, что же мы упускаем (и чтобы убедиться в правильности отслеживания найденного), я воспользовался massif для трассировки действительных выделений динамической памяти. Он довольно медленный, но, по крайней мере, хорошо работает.

Примитивы


Первое, что я обнаружил при трассировке massif — две строки кода, располагавшие в памяти экземпляры базового класса Primitive, не учитываемого в статистике. Небольшой недосмотр, который довольно легко устранить. После этого мы видим следующее:

Primitives 24,67 ГиБ

Ой-ёй. Так что же такое примитив, и зачем вся эта память?

pbrt различает Shape, который является чистой геометрией (сферой, треугольником и т.д.) и Primitive, который является сочетанием геометрии, материала, иногда функции излучения и задействованной среды находящейся внутри и снаружи поверхности геометрии.

Существует несколько вариантов базового класса Primitive: GeometricPrimitive, который является стандартным случаем: «ванильным» сочетанием геометрии, материала и т.д., а также TransformedPrimitive, который представляет собой примитив с применёнными к нему преобразованиями, или как экземпляр объекта, или для подвижных примитивов с преобразованиями, изменяющимися во времени. Оказывается, что в этой сцене оба этих типа являются пустой тратой пространства.

GeometricPrimitive: 50% лишнего пространства


Примечание: в этом анализе сделаны некоторые ошибочные допущения; они пересмотрены в четвёртом посте серии.

4,3 ГБ использовано на GeometricPrimitive. Забавно жить в мире, где 4,3 ГБ использованной ОЗУ — это не самая большая твоя проблема, но давайте тем не менее посмотрим, откуда у нас 4,3 ГБ GeometricPrimitive. Вот соответствующие части определения класса:

class GeometricPrimitive : public Primitive {
    std::shared_ptr<Shape> shape;
    std::shared_ptr<Material> material;
    std::shared_ptr<AreaLight> areaLight;
    MediumInterface mediumInterface;
};

У нас есть указатель на vtable, ещё три указателя, а затем MediumInterface, содержащий ещё два указателя общим размером 48 байтов. В этой сцене всего несколько излучающих освещение мешей, поэтому areaLight почти всегда является нулевым указателем, а влияющей на сцену среды нет, поэтому оба указателя mediumInterface также являются null. Таким образом, если бы у нас была специализированная реализация класса Primitive, которую можно было использовать при отсутствии функции излучения и среды, то мы бы сэкономили почти половину места на диске, занимаемого GeometricPrimitive — в нашем случае примерно 2 ГБ.

Однако я не стал вносить исправление и добавлять в pbrt новую реализацию Primitive. Мы как можно сильнее стремимся минимизировать различия между исходным кодом pbrt-v3 на github и системой, описанной в моей книге, по очень простой причине — поддержание их синхронизации упрощает чтение книги и работу с кодом. В этом случае я решил, что совершенно новая реализация Primitive, ни разу не упоминаемая в книге, будет слишком большим расхождением. Но это исправление определённо появится в новой версии pbrt.

Прежде чем двигаться дальше, выполним проверочный рендеринг:


Пляж с острова из фильма «Моана», отрендеренный pbrt-v3 с разрешением 2048x858 и 256 сэмплами на пиксель. Общее время рендеринга на 12-ядерном/24-поточном инстансе Google Compute Engine с частотой 2 ГГц с последней версией pbrt-v3 составило 2 ч 25 мин 43 с.

TransformedPrimitives: 95% потраченного впустую пространства


Память, выделенная под 4,3 ГБ GeometricPrimitive, была довольно болезненным ударом, но как насчёт 17,4 ГБ под TransformedPrimitive?

Как сказано выше, TransformedPrimitive используется как для преобразований с изменением во времени, так и для экземпляров объектов. В обоих случаях нам нужно применить дополнительное преобразование к существующему Primitive. В классе TransformedPrimitive есть только два члена:

    std::shared_ptr<Primitive> primitive;
    const AnimatedTransform PrimitiveToWorld;

Пока всё хорошо: указатель на примитив и изменяющееся со временем преобразование. Но что на самом деле хранится в AnimatedTransform?
    const Transform *startTransform, *endTransform;
    const Float startTime, endTime;
    const bool actuallyAnimated;
    Vector3f T[2];
    Quaternion R[2];
    Matrix4x4 S[2];
    bool hasRotation;
    struct DerivativeTerm {
        // ...
        Float kc, kx, ky, kz;
    };
    DerivativeTerm c1[3], c2[3], c3[3], c4[3], c5[3];

В дополнение к указателям на две матрицы перехода и связанным с ними временем здесь также присутствует разложение матриц на компоненты переноса, поворота и масштабирования, а также предварительно вычисленные значения, используемые для ограничивания объёма, занятого подвижными ограничивающими параллелепипедами (см. раздел 2.4.9 нашей книги Physically Based Rendering). Всё это добавляет до 456 байт.

Но в этой сцене ничего не движется. С точки зрения преобразований для экземпляров объектов нам необходим один указатель на преобразование, а значения для разложения и подвижных ограничивающих параллелепипедов не нужны. (То есть всего нужно 8 байт). Если создать отдельную реализацию Primitive для неподвижных экземпляров объектов, 17,4 ГБ сжимаются всего до 900 МБ (!).

Что касается GeometricPrimitive, то его исправление — это нетривиальное изменение по сравнению с описанным в книге, поэтому мы тоже отложим его на следующую версию pbrt. По крайней мере, мы теперь понимаем, что происходит с хаосом из 24,7 ГБ памяти Primitive.

Неприятность с кэшем преобразований


Следующим по размеру блоком неучтённой памяти, определённым massif, был TransformCache, который занимал примерно 16 ГБ. (Вот ссылка на исходную реализацию.) Идея заключается в том, что одна и та же матрица преобразований часто используется в сцене несколько раз, поэтому лучше всего иметь в памяти её единственную копию, чтобы все использующие её элементы просто хранили указатель на одно и то же преобразование.

Для хранения кэша TransformCache использовал std::map, а massif сообщил, что 6 из 16 ГБ использовалось для узлов чёрно-красного дерева в std::map. Это ужасно много: 60% процентов этого объёма используется для самих преобразований. Давайте посмотрим на объявление для этого распределения:

std::map<Transform, std::pair<Transform *, Transform *>> cache;

Здесь работа выполнена на отлично: Transform целиком используются как ключи для распределения. Ещё лучше то, что в pbrt Transform хранит две матрицы 4x4 (матрицу преобразования и её обратную матрицу), что приводит хранению в каждом узле дерева 128 байт. Всё это абсолютно излишне для хранимого для него значения.

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

Кроме того, что пространство впустую тратится на ключи, с поиском в std::map для обхода красно-чёрного дерева связано много операций переходов по указателям, поэтому кажется логичным попробовать что-то совершенно новое. К счастью, о TransformCache мало написано в книге, поэтому вполне допустимо полностью переписать его.

И последнее, прежде чем мы приступим: после исследования сигнатуры метода Lookup() становится очевидной ещё одна проблема:

void Lookup(const Transform &t, Transform **tCached,
            Transform **tCachedInverse)

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

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

В новой реализации добавлены следующие улучшения:

  • Она использует хэш-таблицу, позволяющую ускорить поиск, и не требует хранения ничего, кроме массива Transform *, что, по сути, снижает объём используемой памяти до величины, действительно необходимой для хранения всех Transform.
  • Сигнатура метода поиска теперь имеет вид Transform *Lookup(const Transform
    &t)
    ; в одном месте, где вызывающая функция хочет получить из кэша обратную матрицу, он просто вызывает Lookup() дважды.

Для хэширования я использоват хэш-функцию FNV1a. После её реализации я обнаружил пост Араса о хэш-функциях; возможно, мне просто стоило использовать xxHash или CityHash, потому что их производительность выше; возможно, когда-нибудь мой стыд победит и я исправлю это.

Благодаря новой реализации TransformCache значительно снизилось общее время запуска системы, — до 21 мин 42 с. То есть мы сэкономили ещё 5 мин 7 с, или ускорились в 1,27 раза. Более того, более эффективное использование памяти снизило занимаемое матрицами преобразования место с 16 до 5,7 ГБ, что почти равно объёму хранящихся данных. Это позволило нам не пытаться воспользоваться тем, что на самом деле они не проективные, и хранить матрицы 3x4 вместо 4x4. (В обычном случае я бы скептически отнёсся к значимости такого рода оптимизации, но здесь она бы сэкономила нам больше гигабайта — куча памяти! Это определённо стоит сделать в рендерере продакшена.)

Небольшая оптимизация производительности для завершения


Слишком обобщённая структура TransformedPrimitive стоит нам и памяти, и времени: профайлер сообщил, что солидная часть времени при запуске тратилась в функции AnimatedTransform::Decompose(), которая разлагает преобразования матрицы в поворот кватерниона, перенос и масштаб. Поскольку в этой сцене ничего не движется, эта работа не нужна, и тщательная проверка реализации AnimatedTransform показала, что ни к одному из этих значений доступ не осуществляется, если две матрицы преобразования на самом деле идентичны.

Добавив к конструктору две строки, чтобы разложения преобразований не выполнялись, когда они не требуются, мы сэкономили ещё 1 мин 31 с времени запуска: в результате мы пришли к 20 мин 9 с, то есть в целом ускорились в 1,73 раза.

В следующей статье мы всерьёз возьмёмся за парсер и проанализируем то, что стало важным, когда мы ускорили работу других частей.

Let's block ads! (Why?)

[Перевод] Какой была Земля, когда на ней было так же жарко, как нам обещают в 2100 году?

У сегодняшних детей будут свои внуки, когда они доживут до момента, на котором заканчиваются все климатические прогнозы. Нет ли в прошлом каких-то подсказок насчёт нашего будущего?



Карта современной Антарктики, где показана скорость отступления (2010-2016) «линии сцепления», на которой ледники теряют контакт с дном, а также океанские температуры. Одинокая красная стрелочка в восточной Антарктике – это ледник Тоттен, содержащий столько воды, что её хватит на поднятие уровня мирового океана на 3 метра.
Все, что случилось с нами, лишь пролог.
— Уильям Шекспир, «Буря»

2100-й год выглядит, как линия из ограничительных флажков, стоящих на финишной черте изменений климата – будто бы все наши цели заканчиваются именно тогда. Но, перефразируя предупреждение на зеркале заднего вида, он к нам ближе, чем кажется. У сегодняшних детей будут свои внуки, когда они доживут до момента, на котором заканчиваются все климатические прогнозы.
Однако, в 2100-м году климат не перестанет меняться. Даже если мы успешно ограничим потепление в этом веке величиной в 2 ºC, содержание CO2 в воздухе составит 500 миллионных долей (ppm). Такого уровня наша планета не видала со времён середины миоцена, 16 млн лет назад, когда наши предки ещё были человекообразными обезьянами. Тогда температура была выше на 58 ºC, а не на 2 ºC, а уровень моря был выше на 40 метров, или даже больше – не на полметра, которые ожидаются к концу этого века, согласно отчёту межправительственной группы экспертов по изменению климата (IPCC) от 2013 года.

Откуда взялся зияющий разрыв между предсказаниями на конец века и тем, что было в прошлом Земли? Не говорит ли климатическое прошлое планеты нам о том, что мы что-то упустили?

Время


Одна большая причина разрыва проста: время.

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

Медленная реакция такого типа не учитывается в климатических моделях. Это частично происходит из-за недостатка компьютерных мощностей для их обсчёта, частично – поскольку мы концентрируемся только на том, что произойдёт в следующие несколько десятилетий, частично – поскольку эти процессы предсказуемы не на 100%. Но, несмотря на то, что пока климатические модели успешно предсказывают наблюдаемые изменения, неопределённости существуют даже для реакций, происходящих довольно быстро – таких, как образование облаков или усиление потепления на полюсах.

Прошлое Земли, с другой стороны, демонстрирует нам то, как на самом деле проходило изменение климата, суммируя весь спектр быстрых и медленных откликов планеты. Во время прошлых изменений климата, во время которых у Земли были ледяные шапки (как сегодня), она обычно разогревалась на 5 ºC6 ºC при каждом удвоении уровня CO2, при этом на весь процесс уходило порядка тысячи лет. Это примерно в два раза больше значений «равновесной чувствительности климата» (Equilibrium Climate Sensitivity, ECS), используемого в моделях предсказания климата до 2100 года, которые подсчитываются в основном исходя из исторических наблюдений.


«Все, что случилось с нами, лишь пролог» – гравировка на здании национальных архивов в Вашингтоне О.К.

«Мы действительно ожидаем, что системная чувствительность Земли (измените CO2, и на это отреагируют все системы – ледяные шапки, растения, уровень метана, аэрозоли, и проч.) окажется выше ECS. Наше изучение плиоцена говорит, что примерно на 50% выше, хотя и это не предел», — сказал мне Гэвин Шмидт, директор Годдардовского института изучений космоса НАСА в Нью-Йорке.

Или, как сказала Дэйна Ройер из Уэслианского университета: «Проще говоря, климатические модели обычно недооценивают степень изменения климата относительно геологических свидетельств».

Частично за более высокий уровень изменений отвечает медленно реагирующие системы Земли, ответственные за общее потепление. Даже если бы завтра прекратились абсолютно все выбросы парниковых газов, уровень моря будет расти ещё много столетий из-за теплового расширения и таяния ледников; ледяные шапки Антарктики и Гренландии также будут продолжать таять из-за уже накопленной климатом за несколько десятилетий температуры. И поскольку CO2 подолгу остаётся в атмосфере, в отсутствие геоинженерных решений по его удалению мир преодолеет любой предел по температуре, назначенный на конец столетия, и она останется высокой ещё на несколько сотен лет.

Но это не объясняет разрыв полностью, а значит, мы не учитываем ещё какой-то усиливающей обратной связи. Как сказано в национальной оценке климата США 2017 года: «несовпадение моделей с данными по прошлым потеплениям говорит о том, что климатические модели упускают не менее одного, а может и более, процесса, критического для будущего потепления, особенно в полярных регионах».

Сможет ли миоцен поведать нам будущее?


Климатический оптимум середины миоцена (Mid-Miocene Climate Optimum, MMCO) был древним потеплением климата, во время которого уровни CO2 скакнули от менее чем 400 миллионных долей до 500. Содержание CO2 в древности измеряется различными косвенными методами, такими, как содержание изотопов бора и углерода в ископаемых и древних почвах, или по порам на ископаемых листьях. Причиной скачка был редкий вулканический феномен, «крупная пирогенная провинция», во время которого огромные количества базальта были извергнуты на поверхность на западе современной территории США 16,6 млн лет назад. Иветт Элей и Майкл Хрен [Yvette Eley and Michael Hren] из Коннектикутского университета изучали, как это повлияло на климат.

Они пользовались таким инструментом, как молекулы жира, оставшиеся в отложениях после живших в то время растений и микробов. Элей и Хрен извлекли химические останки микробов миоцена из грязей того периода в Мэриленде, а затем пересчитали процентное содержание различных жировых молекул в температуру почвы, используя калибровки, основанные на более чем десятилетнем изучении микробных жиров в современных почвах со всей планеты. «Определённо время появления этих базальтовых потоков и время изменения климата очень тесно связаны, — сказала Элей. – Наши биомаркеры определённо отслеживают поведение CO2. Что бы ни вызвало изменения в системе экологии планеты, оно определённо следовало за pCO2».

Но среди различных примеров климатических колебаний MMCO был очень мягким, по сравнению с концом пермского периода, триасового периода и других событий, связанных с массовыми вымираниями. Выбросы CO2 в миоцене были достаточно медленными, чтобы избежать значительного окисления океанов, в отличие от сегодняшнего дня или экстремальных примеров из прошлого.

Они схожим образом подсчитали и температуру морей, используя химические останки морских микробов: «Мы получили относительное изменение температуры поверхности моря во время MMCO на 4-5 градусов – а тогда температура моря была на 6 градусов больше сегодняшней», — сказала Элей.

Теплее, влажнее, суше?


Они измерили влажность атмосферы в миоцене, анализируя химические остатки воскового покрытия листьев растений, откалибровав их по современным значениям в различных местах планеты. «Если использовать воск с листвы, наш биомаркер, в качестве показателя влажности атмосферы, то мы приходим к выводу, что в середине миоцена атмосфера становилась более влажной, — сказала Элей. – Довольно интересно рассматривать нашу работу в контексте других реконструкций. Запад современной территории США стал более сухим, Южная Америка более влажной, части Европы более влажными, а другие части – более сухими».

Такие удалённые места, как восточное побережье США, тихоокеанский северо-запад, западный Китай, Патагония, центральная Азия и Атакама в Южной Америке стали гораздо более влажными, что привело к увеличению глобальной эрозии. В результате произошло расширение площади лесов и их уплотнение. Интересно, что в Северной Африке или Азии не было признаков пустынь, а сейчас у нас есть пустыни Сахара и Гоби.

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

Хотя ещё до середины миоцена на планете было очень много лесов (в отличие от сегодняшнего дня, отражающего процесс обезлесения, которому способствовали люди, несколько тысячелетий жившие между ледниковыми периодами), потепление в миоцене привело к чётко наблюдаемым изменениям растительности по всему миру, которые сохранились в ископаемом виде, особенно в виде окаменелой пыльцы.

На большей части Европы субтропические растения пришли на смену адаптировавшимся к холоду растениям, а густые леса с обилием болот заполонили берега и дельты рек на территориях современных Дании и Германии (тогда береговая линия Европы была на 190 км глубже в сторону земли, чем сегодня). Эти болота накапливали бурый уголь, сегодня обеспечивающий четверть генерации электроэнергии Германии. Испания сопротивлялась тенденции к увлажнению при помощи жаркого и сухого климата на юге и тёплого и влажного климата на севере, точно как сегодня, и испытывала долгие сухие сезоны.


Жизнь в середине миоцена на территории современной Испании в представлении художника

Судя по европейским растениям, между сезонами перепад температур был меньше.

В Сибири дожди шли в 3-5 раз чаще, чем сегодня, а болота на востоке России тоже накапливали уголь. В арктической Канаде, где сегодня находится тундра с вечной мерзлотой и без деревьев, в середине миоцена низкотемпературные леса из берёз, вязов, падубов и зонтичной сосны сменились высокотемпературными лесами, где рос бук, орешник, амбра, грецкий орех и липа.

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

Но больше всего изменилась Антарктика.

Подъём уровня моря на 40 метров


Растаялоот трети до трёх четвертей Антарктического льда. На земле, освободившейся ото льда, появилась тундра и леса, состоящие из буков и хвойных деревьев, чего не могло бы быть, если бы Антарктическим летом не было бы теплее 10 ºC (это гораздо теплее, чем сегодняшние -5 ºC). Неясно, чем занималась Гренландия, но на её севере мог быть небольшой ледяной покров, довольно сильно растаявший.

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

40 метров – это лишь немногим больше последних предсказаний подъёма уровня моря недалёкого будущего: до метра к 2100 году и до 1,6 метров (когда под водой окажутся места проживания 5% населения мира) к 2300 году, при условии, что мы стабилизируем потепление на уровне около 2 ºC. Разница только во временных масштабах. Согласно национальной оценке климата США от 2017 года, 2 ºC потепления приведёт к потере 3/5 частей льда Гренландии и одной трети льда Антарктики, что приведёт к повышению уровня моря на 25 м – правда, за 10 000 лет.

И всё же, сведения из миоцена говорят о том, что современное поднятие уровня моря может оказаться более сильным и быстрым.

Береговые отложения восточной Антарктики демонстрируют, что её льды были чрезвычайно чувствительны даже к небольшим изменениям уровня CO2 и колебаниям орбиты в миоцене, и могли таять довольно быстро. Насколько быстро? Эдвард Гассон из Шеффилдского университета Британии подсчитал, что Антарктика могла изначально повышать уровень моря примерно на 2,5 м каждые сто лет, а затем этот процесс замедлился, и за 10 000 лет уровень стал выше на 30-36 метров. Эта скорость совпадает с оценками Роберта Деконто из Пенсильванского университета и Дэвида Полларда из Амхерстского колледжа, сделанными на основе плиоцена, климат которого был прохладнее, чем в середине миоцена, а уровень моря «всего» на 20 м выше, чем сегодня. Деконто и Поллард предположили, что современное потепление на 2,5 ºC к 2100 году повысит уровень моря на 5,7 м к 2500-му году – примерно на 1,2 м в столетие. Это быстрое изменение может показаться радикальным, но нам известно, что периодически за последние 500 000 лет уровень моря поднимался на 4-5,7 м каждые сто лет.

Если современный подъём уровня моря окажется похожим на тот, что был в плиоцене, 1,2 м за сто лет, или в миоцене, 2,4 м за сто лет, а не как у IPCC – на полметра за век, то наше будущее будет совсем иным. Поднятие уровня моря, усиленное приливными затоплениями и штормами, сделает огромное количество прибрежной инфраструктуры и владений бесполезными уже через пару поколений.

И до сих пор компьютерные модели не поддерживали такую большую скорость таяния льдов.

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

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

Отступление льда усиливает потепление, поскольку яркая, отражающая свет поверхность заменяется тёмной, поглощающей тепло водой и землёй. В результате, температуры будут медленно расти и дальше.


Как мог выглядеть ледяной щит Антарктики в миоцене, от 14 до 23 млн лет назад

Надежда на неопределённость?


Может ли разрыв между климатом миоцена и нашим предполагаемым будущим существовать просто из-за недостатка и неточности данных по древнему климату?

«Изменения уровня CO2 в среднем миоцене может превышать расчётное медианное значение. О других факторах вообще ничего не известно. Уровни метана или N2O не определены. Количество озона или сажи (появляющейся после пожаров или в результате жизнедеятельности растений) тоже мало известно, — рассказал мне Гэвин. – Поэтому, даже если бы у нас были идеальные индикаторы глобальной температуры (а их нет), оценки чувствительности, полученные простым делением температуры на уровень CO2 нельзя сравнить с сегодняшними оценками ECS».

И всё-таки, несмотря на разброс значений уровня, они имеют тенденцию скапливаться вокруг значения в 500 ppm для среднего миоцена. Некоторые исследования даже говорят о возможности более низкого уровня CO2, приведшего, тем не менее, к более высоким температурам. Картину относительно тёплого климата поддерживают геологические свидетельства о высоком уровне моря и найденные ископаемые по всему миру, включая морское дно неподалёку от берегов Антарктики.

Был ли климатический оптимум увеличен из-за циклического изменения орбиты? Хотя отдельные ледниковые циклы миоцена и зависели от орбитальных колебаний, как это было с последним ледниковым периодом, тёплая погода и максимальное отступление льда сохранялись на протяжении нескольких орбитальных и ледниковых циклов, наравне с более высокими уровнями атмосферного CO2. Так что мы не можем повесить повышение оптимума только лишь на орбиту Земли вокруг Солнца.

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

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

Если всё это покажется вам слишком депрессивным, то знайте – надежда есть! Она заключается в малой скорости реагирования Земли, которая приоткрывает нам небольшое окно возможностей.

Рука в огне


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

Хотя льды Гренландии и западной Антарктики уже тают с ускорением, восточная Антарктика – пока что – остаётся в относительно стабильном состоянии (за исключением ледника Тоттен). Так что, если мы удержим потепление сильно ниже 2 ºC, модели Деконто и Полларда говорят о том, что восточная Антарктика не внесёт существенного вклада в повышение уровня моря в будущем.

Но для этого нам потребуется уменьшить концентрацию парниковых газов, и перевыполнить планы программы Net Zero.

"Отрицательные выбросы" (активное поглощение CO2 из воздуха) может медленно уменьшить глобальные температуры и стабилизировать множество факторов повышения уровня моря в XXII веке. Согласно Матиасу Менгелю из Потсдамского исследовательского института влияния на климат, падение уровней CO2 в итоге позволит Антарктике начать медленно накапливать лёд, поэтому уровни моря снова начнут падать где-то через три сотни лет.

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

Наше текущее окно возможностей не будет оставаться открытым долго – учёные пытаются понять, не начался ли уже коллапс ледяных щитов у одного из крупнейших ледников западной Антарктики. «Всё меняется очень, очень быстро по сравнению со всем, что мы находили в геологических записях, — говорит Элей. – Мне бы очень хотелось верить, что у нас на руках не окажется один из наиболее худших сценариев, но мне кажется, что мы уже стоим на пути к этим уровням [CO2]».

«В середине миоцена уровень CO2 поднимался на 100-200 ppm. С начала индустриальной эпохи мы уже добрались до повышения в 127 ppm. Так что мы уже наполовину прошли этот путь, — сказал Хрен. – Неопределённость заключается не только в том, к каким уровням CO2 мы в итоге придём, но и в том, как система среагирует на такие быстрые изменения».

Let's block ads! (Why?)