Как протащить верблюда сквозь игольное ушко, или обновление компилятора С++ на проекте старше 10 лет
Привет! Меня зовут Колосов Денис, я являюсь разработчиком клиентской части проекта «Allods Online» в студии IT Territory. Сегодня я расскажу о том, как мы решились обновить среду разработки и заодно компилятор на нашем проекте с Visual C++ 2010 на 2019.
О чем пойдет речь?
- Как мы докатились до такой жизни и отважились на этот шаг;
- О сборке вендерских библиотек и всего окружения, которое у нас есть;
- С какими кастомными проблемами мы столкнулись;
- К чему это все привело.
Что касается сборки вендерских библиотек, затрону буквально в нескольких предложениях и больше возвращаться к теме не буду, т. к. в этом плане нам повезло. Во-первых, добрая их половина у нас есть в исходниках и лежит в отдельной папке в репозитории. 90% этих вендоров собираются прямо из solutions — они спокойно конвертируются из 2010 версии в 2019. Во-вторых, все недостающие библиотеки нашлись в vcpkg. Так что всё обновление свелось к монотонной конвертации проектов и выполнению vcpkg search и vcpkg install.
Ну а теперь немного предыстории.
Началось всё случайно. Как в «Магазинчике БО», история пишется дохлыми зайцами. В один прекрасный день пришёл ко мне коллега по проекту и спросил: «Ден, доколе?! Доколе ради простейших операций со строками мне придётся создавать копии, делать бессмысленные аллокации? Ведь давно уже есть string_view…». Так что, считай, благодаря «дохлому» string мы и решили, а не замахнуться ли нам… ну и замахнулись.
В тот момент проект сидел на Visual Studio 2010, и новые версии стандарта C++ с соответствующими печеньками госдепа нам только снились.
Так что мы хотели получить?
- Потенциальный буст производительности — без оценок, потому что не знали, к чему бы это привело, особенно в проекте, которому больше 10 лет;
- Возможность включать те сторонние библиотеки, на которые мы давно смотрели, но по тем или иным причинам не могли с ними работать (EASTL, Optick Profiler и т. д.);
- Сокращение времени разработки;
- Прокачать командные скилы. Применить на практике все возможности современного C++, т. к. оставаться на С++ 0x в 20-х годах XXI века — это профессиональная деградация.
А теперь — с чем столкнулись:
- Краши — сразу при запуске клиентского приложения из-под отладчика (delete(void*));
- Deadlocks — подтянулись спустя n недель. На наше счастье, он такой был один, и быстро удалось его отловить, а потом нагуглить, в чем причина (Thread-safe Local Static Initialization);
- Проблемы с позиционированием объектов в мире: террейн, например, улетел вникуда, а за ним мобы и все остальное (FPU control word);
- Магия с шаблонами и макросами;
- Исключительно кастомная ошибка: при запуске финальной сборки клиента игры мы проверяем раздел экспорта .exe-файла. Он должен быть пустым. Это требование связано с системой защиты проекта. Но в .export-секции оказалось очень много чего интересного, о чем я и расскажу в заключительной части (_CRT_STDIO_INLINE).
Но обо всем по порядку.
Краши (USER-DEFINED OPERATOR DELETE(VOID ))
- Краши происходили из-за нашего кастомного аллокатора памяти на основе dlmalloc: наверное, не секрет ни для кого, что игровые проекты не используют стандартные аллокаторы, которые не заточены под специфику игр.
- Стандартный аллокатор не блещет производительностью, что является краеугольным камнем игровых проектов. Кроме того, для игр очень страшна фрагментация памяти. Поскольку они очень “memory-consumption”, если адресное пространство сильно фрагментировано, то память быстро «заканчивается», и происходят креши. Наверное, для 64-битных игр это не критично, но для 32-битных, как у нас — весьма.
- В MinGW для проектов, которые собираются на C++ 14 и динамически линкуют стандартную библиотеку libstdc++, не вызывается переопределенный скалярный оператор delete(void ), если не переопределена его sized-версия (GCC Bugzilla – Bug 77726).
- Оказалось, что в компиляторе Microsoft Visual C++ (по крайней мере, версии 14.21) есть похожая «особенность». Об этом баге добрые люди даже сообщали в Microsoft (Developer Community), но мы об этом узнали, уже справившись с проблемой. К чести товарищей из «Сиэтловской области», они эту «особенность» пофиксили.
Итого: переопределили sized-версию delete — и краши пропали. Вот так наступила перемога:
void __cdecl operator delete( void* ptr ) noexcept < a1_free( ptr ); >void __cdecl operator delete( void* ptr, size_t /*sz*/ ) noexcept < a1_free( ptr ); >void __cdecl operator delete[](void* ptr) noexcept < a1_free( ptr ); >void __cdecl operator delete[]( void* ptr, size_t /*sz*/ ) noexcept
Здесь a1_free( ptr ) — наша собственная функция освобождения памяти.
Тут же хотелось бы отметить один интересный факт. Давайте посмотрим на разделы импорта одной из библиотек нашего проекта DataProvider.dll, занимающейся подтягиванием ресурсов игры (этот факт справедлив для всех библиотек проекта).
Как мы видим, в сборках Visual C++ 2010 и Visual C++2019 раздел импорта отличается. Debug-версии отличаются только наличием sized-версии operator delete в сборке Visual C++ 2019, а вот в Release-сборке версии 2019 вообще отсутствуют operator new/delete. Это отдельный интересный вопрос, который стоит задать компилятору и линковщику.
Далее нас ждали любимые дедлоки, связанные с инициализацией локальных статических переменных.
Thread-Safe Local Static Initialization
Существует интересный флажок компилятора /Zc:threadSafeInit, который сообщает ему, что инициализировать локальные статические переменные нужно в thread safe режиме. MSDN говорит, что поведение не определено, если происходит рекурсивная инициализация — то есть, поток выполняет функцию foo, содержащую объявление статической переменной var, и доходит до инициализации этой переменной. Переменная var представляет собой экземпляр очень хитро реализованного класса, конструктор которого может ещё раз вызвать функцию foo. По умолчанию флажок /Zc:threadSafeInit включен в Visual Studio 2015 и выше. Поэтому в нашем случае поведение оказалось вполне себе определено — бесконечный цикл ожидания инициализации переменной.
Вот небольшой кусочек кода, наглядно иллюстрирующий работу флажка /Zc:threadSafeInit. Помимо собственного глобального аллокатора мы используем статические типизированные пулы для часто создаваемых/разрушаемых объектов.
#define DEFINE_STATIC_POOL( ElementType, ElementsCount, PoolVarName ) \ static FORCEINLINE Mem::static_pool &PoolVarName() \ < \ static Mem::static_pool__instance; \ return __instance; \ > \ class StaticPoolCreator##PoolVarName \ < \ public: \ StaticPoolCreator##PoolVarName() \ < \ PoolVarName(); \ >\ > static creator##PoolVarName; >
Здесь мы объявляем статическую функцию со статической переменной instance внутри, стандартный синглтон Майерса. Затем объявляем класс, в конструкторе которого вызывается определенный нами синглтон, и объявляем экземпляр данного класса статическим. Такие телодвижения с известным ударным инструментом необходимы, чтобы ввести в заблуждение вероятного противника (как не в себя оптимизирующий компилятор) и не раздувать секцию .data результирующего .exe-файла клиента игры.
А так выглядит наш поток сознания в assembler:
7BC04944 call __Init_thread_header (7BBC247Dh) 7BC04949 add esp,4 7BC0494C cmp dword ptr ds:[7BD00944h],0FFFFFFFFh 7BC04953 jne event_sound3d_pool+59h (7BC04979h) 7BC04955 mov ecx,offset __instance (7BCDC4F8h) 7BC0495A call Mem::static_pool::static_pool (7BBC1569h) 7BC0495F push offset `event_sound3d_pool'::`2'::`dynamic atexit destructor for '__instance'' (7BC6C130h) 7BC04964 call _atexit (7BBC4DF4h) 7BC04969 add esp,4 7BC0496C push 7BD00944h 7BC04971 call __Init_thread_footer (7BBC3652h)
Init_thread_header — функция Visual C++ Runtime, исходники которой можно посмотреть здесь: vcruntime/thread_safe_statics.cpp. Она начинает потокобезопасный блок инициализации статической переменной. Достигается это путем использования двух вспомогательных счетчиков и флажка, которые управляют этапами инициализации переменной.
Далее мы регистрируем деструктор нашей статической переменной и вызываем функцию Init_thread_footer.
А здесь работает критическая секция, которая управляет доступом к описанным счетчикам и флажкам:
extern "C" void __cdecl _Init_thread_lock(): 7BC63350 push ebp 7BC63351 mov ebp,esp 7BC63353 push offset _Tss_mutex (7C051218h) 7BC63358 call dword ptr [__imp__EnterCriticalSection@4 (7C0521E0h)] 7BC6335E pop ebp 7BC6335F ret
После того, как мы разобрались с зависанием игрового клиента, мы столкнулись с ещё более интересной проблемой: отъехали координаты практически всех объектов в игровом мире.
FPU Control Word
x87 FPU Control Word — это управляющее слово математического сопроцессора, с помощью которого можно управлять режимом округления, точностью, а также маскировать различные исключения. Существует определённый набор API для работы с этим control word — например, функция _controlfp_s. Она позволяет как прочитать, так и записать управляющее слово.
Касаемо последней API — у нее есть сайд-эффекты, выражающиеся в том, что она, в зависимости от аппаратной платформы, затрагивает управляющий регистр SSE2( MXSCR- x86/x64), где также модифицирует флаги округления и не только.
К чему такая долгая предыстория? Дело в том, что, когда мы побороли краши и зависания и смогли на свежесобранной версии попасть в игровой мир, там нас ждал очень неприятный сюрприз. Странным образом отвалился террейн, все мобы и персонажи в мире упали в бездну, кто находился на каких-то объектах, участвовали в каком-то броуновском движении. Здания повисли в воздухе, а часть объектов взлетела в небо. К сожалению, в тот момент я не наделал скриншотов, чтобы поделиться этим глобальным апокалипсисом. Но, в целом, картина выглядела довольно удручающе. Всему виной оказалась одна из вендорских библиотек, которая меняла режим округления вещественных чисел: вместо округления к ближайшему целому отбрасывалась дробную часть.
Вкратце коснемся системы позиционирования «Аллодов». Она базируется на кубах размером 32x32x32 и смещениях внутри них. Игровая позиция задаётся парой векторов Position< < int, int, int >, < float, float, float >>, и любая позиция приводится к этому виду методом Position::Normalize(). Всё решение проблемы заключалось в модификации этого метода следующим образом:
FORCEINLINE void Position::Normalize()
Метод Normalize предназначен для преобразования данных внутри Position в валидную позицию игрового мира. В начале метода мы сохраняем текущее значение управляющего слова и устанавливаем флаг, который меняет режим округления. Затем происходит преобразование позиции, после чего восстанавливается режим округления, который был до вызова нашей функции.
Почему так криво? Дело в том, что в отсутствие времени на выяснение поведения вендорской библиотеки в случае масштабного вмешательства в режим округления было принято решение пойти методом наименьшего сопротивления — «Чтобы ничего не поломать».
Шаблоны и макро-магия
Поборов, как казалось, основные трудности обновления, когда мы уже готовились замерять буст производительности, вылезла ещё одна проблема. В одном из кейсов общения с определенными мобами вылетел новый краш. Причина оказалась в коде, который был закомментирован в начале процесса обновления, чтобы просто собрать и запустить всё остальное.
Дело вот в чем. Мы объявляем массив структур с помощью запутанных макросов. Затем один из макросов генерит в каждой структуре указатель на функцию с типом lua_CFunction. Внутри каждой функции будет вызываться соответствующий объявлению метод класса Sound::ISound2D. Например, первый элемент массива генерирует структуру с функцией, которая будет вызывать метод bool Sound::ISound2D::Play( void ) и т.д.
DEFINE_LUA_STRONG_METHODS_START( Sound::ISound2D ) < "Play", OBJECT_LUA_FUNCTION( bool, Sound::ISound2D, Play, void ) >, < "Stop", OBJECT_LUA_FUNCTION( bool, Sound::ISound2D, Stop, bool ) >,
Error C2440 ‘initializing’: cannot convert from ‘int (__cdecl *)(lua_State *)’ to ‘lua_CFunction’
Эту ошибку изначально мы временно решили путём комментирования кода. Но, как известно, в России нет ничего постояннее временного. Так комментарий и прожил до завершающего этапа обновления компилятора, пока не напомнил о себе.
Интересна ошибка тем, что проблемный тип функции определён где-то в недрах LUA-библиотеки следующим образом:
typedef int (lua_CFunction) (lua_State L);
Как мы видим, компилятор не может привести друг к другу два идентичных типа указателей на функции. __cdecl в объявлении типа lua_CFunction ни на что не влияет, т.к. дефолтным соглашением о вызовах в C++ как раз и является __cdecl. Так что типы совершенно идентичны.
Путем очень въедливого чтения сообщений компилятора стало понятно, что дело только в объявлениях вида:
В то время как объявление:
— недовольств компилятора не вызывает. Разницы между строчками практически никакой, кроме типа последнего параметра метода класса. Однако, первый вариант упорно не нравится компилятору, а вот со вторым всё в порядке. Поэтому проблема решилась простой заменой во всех проблемных случаях void на bool.
Из-за большого количества макросной магии и её не принципиальной важности разбирательства с ней сошли на нет. Но осталась задача на будущее — разобрать данное отличие поведения компиляторов MS VC 2010 и MS VC 2019.
_CRT_STDIO_INLINE
Как и любой проект, «Аллоды» имеют несколько конфигураций сборки, и вот на этапе сборки «финальной» конфигурации, которая и распространяется через Игровой центр MY.GAMES (назовём её FINALRELEASE), мы столкнулись с заключительной на сегодня проблемой.
Ниже приведен скриншот, функции на котором наверняка многим знакомы:
Как я уже говорил, при запуске финальной версии игры происходит проверка раздела экспорта на предмет его «девственной» чистоты. И скриншот показывает, что наша проверка не проходит. Но интересен не сам факт провала проверки, а функции, попавшие в .export-секцию, которые и фейлят проверку. Как нетрудно заметить, это API библиотеки stdio.
Давайте взглянем на то, как определяются данные API:
#if defined _NO_CRT_STDIO_INLINE #undef _CRT_STDIO_INLINE #define _CRT_STDIO_INLINE #elif !defined _CRT_STDIO_INLINE #define _CRT_STDIO_INLINE __inline #endif
_Check_return_opt_ _CRT_STDIO_INLINE int __CRTDECL _fprintf_l( _Inout_ FILE* const _Stream, _In_z_ _Printf_format_string_params_(0) char const* const _Format, _In_opt_ _locale_t const _Locale, . ) #if defined _NO_CRT_STDIO_INLINE ; #else < int _Result; va_list _ArgList; __crt_va_start(_ArgList, _Locale); _Result = _vfprintf_l(_Stream, _Format, _Locale, _ArgList); __crt_va_end(_ArgList); return _Result; >#endif
Объявление выглядит довольно логичным и направленным на избавление от накладных расходов на функциональные вызовы. Но в нашем проекте такое объявление оказалось не предусмотрено.
Причина проблемы оказалась в библиотеке LuaJIT(a Just-In-Time Compiler for Lua). А вернее — в ее сборке. В проекте она собирается с помощью .bat-файла, в котором оказались интересные строки:
. . . . . . . @setlocal @set LJCOMPILE=cl /MD /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline /I"include" /I"src" /Fo"obj/" @set LJLINK=link /nologo @set LJMT=mt /nologo @set LJLIB=lib /nologo /nodefaultlib @set DASMDIR=dynasm @set DASM=%DASMDIR%\dynasm.lua . . . . . . .
Макрос D_CRT_STDIO_INLINE определяется образом, указанным выше, и затем передается компилятору. Таким образом, D_CRT_STDIO_INLINE определяется как __declspec(dllexport)__inline. С точки зрения компилятора, а заодно и здравого смысла, определение функции с префиксом __declspec(dllexport)__inline вполне законно, и на практике приводит к вполне логичным и ожидаемым результатам. Грубо говоря, компилятор заменяет вызовы функции внутри библиотеки, где она реализована, и где он может это сделать, на её тело. Но также он помещает её в раздел экспорта данной библиотеки.
Проблема в том, что LuaJIT используется в проекте в виде статической библиотеки, и таким образом весь её этот экспорт переходит в наш результирующий exe-файл. Как зачастую случается, решение самой проблемы выглядит тривиальным на фоне выяснения причин этой проблемы.
Итоги
- Первое и самое главное — мы апдейтили проект до стандарта ISO C++ 17. И, наконец, получили возможность применять современные стандарты в разработке.
- Количество аллокаций в кадре снизилось в разы. В определённых моментах, например, с 600-700 до 200-250. Да, это всё-равно громадное значение, и далеко ещё не самое высокое. Но прогресс заметен.
- FPS увеличился в среднем на ~10-15% в «гладком» кадре.
Что такое «гладкий» кадр? Будем считать, что это кадр, не нагруженный большим количеством интерфейсных событий. Например, даже этот относительно лёгкий замес порождает огромное число сообщений для апдейта интерфейса:
А вот так выглядит «гладкий» кадр:
4. Получили возможность дальнейшей оптимизации кодовой базы проекта на основании последних нововведений стандартов C++11/14/17.
5. Время сборки проекта и размер результирующего exe-файла клиента сколько либо заметно не изменились, что также является плюсом.
Эпилог
Итак, основных поставленных целей мы достигли. Но были и приятные неожиданные бонусы. Разумеется, разработчики компиляторов не стоят на месте и стараются создавать всё более оптимизирующие версии, но даже с учётом этой тенденции один из примеров стал для меня откровением.
Я решил посмотреть asm-код одного из тестов SSE-функций. Результат Visual C++ 2019 превзошел старую версию, как гроссмейстер школьника. При максимально идентичных настройках там, где Visual C++ 2010 просто заменил вызов inline-функции на соответствующую SSE-инструкцию, 2019-я версия увеличила шаг цикла и применила аналогичные требуемой AVX-инструкции. С учётом кода теста оптимизация выглядела вполне закономерной, но только старая версия не делала даже намёков на неё.
Если перед кем-то стоит аналогичная задача, но пугают масштабы и сомнительный профит, нужно обязательно браться за неё, несмотря ни на какие сложности и ограничения. Профит будет в любом случае. Вы получите интереснейший опыт, решите множество сложных и интересных сопутствующих задач, а главное — не будете стоять на месте, что аналогично безнадежному отставанию.
И на самый-самый конец: а еще здесь можно ознакомиться со списком вакансий в нашей студии.
- Блог компании MY.GAMES
- Программирование
- C++
- Разработка игр
Бойко М. Как протащить верблюда сквозь игольное ушко
Вспомним: на дворе – канун 1992 года. «Умные головы» по телевизору, в газетах, в представительных собраниях озабоченно дискутируют на тему: готова ли Россия к рынку? Всерьез обсуждается проблема: а можно ли вообще в нашей стране проводить приватизацию? Поймут ли «наши люди», что такое аукцион? Это сегодня подобные сентенции кажутся по меньшей мере смешными. А тогда… Осененные степенями и званиями ученые люди глубокомысленно рассуждали о том, что рынок – это не для нас; озабоченно отыскивали некий «третий путь», по которому должна пойти Россия.
На фоне всей этой теоретической дичи в стране вовсю развернулась спонтанная приватизация. Директора предприятий, руководители министерств и ведомств действовали в полном соответствии с экономической логикой: делали свой маленький (а кто и не очень) бизнес. Правда, они не могли извлекать личную выгоду законным путем. Хотя они и контролировали предприятия, но не были их владельцами и потому не могли получать прибыль открыто, законно. Поэтому заключались контракты на продажу продукции по заниженным ценам, помещения и производственное оборудование сдавалось в аренду подставным фирмам, выдавались кредиты, которые потом не возвращались, – все это, конечно, с учетом личной заинтересованности директора. И пока «ученые мужи» дискутировали о том, поймет ли русский народ, что такое прибыль и дивиденды, самые шустрые представители этого народа уже энергично преумножали свои доходы, пуская на ветер формально остававшуюся государственной собственность.
Масштабы бесконтрольного воровства росли и ширились, и власть, сознавая, что надо вмешаться, не понимала, как это сделать. Было понятно, что грабежу попустительствовать нельзя. Но, с другой стороны, было совершенно ясно, что остановить этот разгул административным путем тоже невозможно: уже не те.
Однако мы прекрасно отдавали себе отчет, в какой системе координат оказалась страна, понимали, что только законная, хорошо организованная приватизация может остановить приватизацию спонтанную и воровскую. Однако для того чтобы директора, вкусившие уже плодов стихийной приватизации, приняли этот вариант, нужно было идти на существенные уступки им. Единственный выход виделся в том, чтобы превратить директоров в настоящих собственников: дать им законное право получать доход от предприятий, которые они контролируют. А заодно сделать их ответственными за все, что происходит на этих предприятиях. Иными словами, директора надо было превратить в акционера.
Нет, это была не слабость. И не ошибка. Это был единственно возможный в той ситуации политический компромисс, на который мы шли совершенно сознательно и преднамеренно. Ведь с начала 1992 года фактически главным был политический вопрос: позволит ли «директорский корпус» продвигаться гайдаровским реформам? Это сейчас директора утратили роль мощнейшего политического клана, а тогда их сила казалась почти абсолютной. Было ясно, что провести приватизацию, а по большому счету и всю реформу, наперекор их воле невозможно.
Кроме того, надо было учитывать не только фактор политической немощи власти, но и организационную слабость только что сформированного российского правительства. У новых людей, пришедших во власть, было понимание общей логики реформ, но не хватало опыта организационной, аппаратной работы. Старые же аппаратчики поначалу совсем плохо понимали новые задачи и нередко саботировали их решение: кто втихую, а кто и открыто. Мы прекрасно отдавали себе отчет в наличии этих ограничений – и политических, и организационных.
В итоге, учитывая все вышеперечисленное, мы пришли к выводу, что сделать приватизацию «правильно», по классическим канонам, чтобы она от начала и до конца отвечала исключительно государственным интересам, невозможно. Для того чтобы приватизация состоялась, она должна была быть политически приемлемой и практически осуществимой.
Теперь читателю понятно, почему пришлось вводить льготы и отдавать директорам и работникам предприятий хороший кусок собственности. В смысле вся наша приватизация оказалась льготной. Нам важно было получить поддержку самых разных политических и общественных сил: директоров, рабочих, региональных властей, народа в целом. Всех их мы должны были превратить в своих союзников. Именно это обстоятельство во многом продиктовало выбор стратегии приватизации.
Первоначальный вариант льгот, заложенный в программу приватизации, состоял в том, что 25 процентов привилегированных (без права голоса) акций приватизируемого предприятия бесплатно распределялись среди работников. Кроме того, члены трудового коллектива имели право приобрести еще 10 процентов обыкновенных (голосующих) акций за деньги, но с скидкой от их номинальной стоимости. А руководству отдавалось еще 5 процентов, но уже без скидок, по номинальной стоимости.
Несмотря на то, что уже первый вариант приватизации с точки зрения уступок трудовым коллективам и директорам был беспрецедентен для мировой практики, давление на правительство продолжалось. Это давление в значительной степени осуществлялось через Верховный Совет, с трибун которого безостановочно неслись требования «отдать фабрики рабочим». И результатом компромисса с директоратом и законодателями стал второй вариант приватизации.
В соответствии с ним под контроль работников предприятия уже уходил 51 процент голосующих акций, то есть контрольный пакет. Все акции надо было выкупать по цене, в 1,7 раза превышающей номинальную. Впрочем, удалось настоять на том – и это было очень важно, – что акции приобретаются в собственность отдельного работника, а не всего коллектива. И каждый работник в любой момент имеет право распоряжаться своими акциями самостоятельно. Это открывало возможность появления эффективного собственника на предприятии не в процессе приватизации, а уже после ее завершения.
я и тогда полагал, и сегодня считаю: по второму варианту слишком много льгот даровали директорату и работникам предприятий, пойдя у них на поводу. Можно было поторговаться и попробовать отдать не 51 процент, а несколько меньше. Скажем, 40. Это был вопрос политического расчета.
Но, в целом, жизнь показала, что наша стратегия оказалась правильной. Когда стали известны основные контуры предлагаемой программы приватизации, в особенности второго варианта льгот, сопротивление директоров приватизации и реформам в целом перестало носить массовый характер. Вся борьба сводилась уже к выторговыванию особых схем приватизации, смысл которых, как правило, заключался в том, что директор хотел получить еще больше собственности, чем предписывали правила.
Сейчас мы испытываем немало проблем, связанных с оставшимися у руля директорами. Многие из них так и не смогли начать работать и тормозят реформы на своих предприятиях. Это и есть тяжелое наследие того старого политического компромисса. Но если бы не тот компромисс, то вообще не было бы никаких проблем, потому что не было бы приватизации как таковой.
Однако некоторым директорам и 51 процент показался малым! Под их ожесточенным давлением появился третий вариант приватизации: на предприятиях средних размеров руководство получало право выкупить 40 (!) процентов акций по очень низким ценам. С огромным трудом удалось исключить из этой схемы крупные предприятия, мотивируя это тем, что превращение в один прекрасный день тысяч директоров в мультимиллионеров спровоцирует народный гнев. Впрочем, интерес директоров к совсем уж грабительскому третьему варианту удалось ограничить одной существенной оговоркой. Руководителям предприятии давали право выкупать свой пакет только в том случае, если они обещали, что сумеют избежать банкротства. В итоге количество претендентов на третий вариант оказалось незначительным: не более 2 процентов предприятий. Директора панически боялись банкротств.
Несмотря на то, что принятие второго варианта помогло прохождению программы приватизации через Верховный Совет, дискуссии по поводу альтернативных вариантов льгот не прекращались и после этого. Одним из оппонентов правительства выступала группа московского экономиста Ларисы Пияшевой. Несмотря на впечатляющую капиталистическую риторику, госпожа Пияшева настаивала на быстрой массовой приватизации путем передачи имущества трудовым коллективам – целиком и бесплатно. Это привело бы к увековечиванию власти старых директоров, и приход эффективного собственника на предприятие был бы практически невозможен не только в ходе, но и после приватизации. Естественно, директорат приватизацию по Пияшевой поддерживал с восторгом.
Кроме того, отраслевые министры активно проталкивали идею нового механизма приватизации через создание групп, которые фактически контролировались бы министерствами.
Все эти варианты не гарантировали программе приватизации полной безопасности. Идти на дальнейшие уступки директорам и трудовым коллективам означало бы завести экономику в такие дебри, из которых выбраться было бы уже невозможно. Чтобы приватизация не захлебнулась, требовалось обратиться за поддержкой ко всему населению. На повестку дня встал вопрос о подготовке и проведении массовой приватизации.
Главный компромисс
И опять дискуссия. А нужна ли вообще России быстрая массовая приватизация? Нам всячески пытались доказать: чем медленнее, тем лучше. Многие российские придерживались такой точки зрения. Кроме того, была еще одна интересная группа лоббирования в этом направлении: западные инвестиционные банки, которым в массовой бесплатной приватизации просто не оставалось места. В случае же приватизации за деньги они могли получать хорошие комиссионные с каждой сделки.
Помнится, один из самых авторитетных в мире инвестиционных банков – «Голдмэн Сакс» – в то время очень активно пробивал приватизацию Новомосковского завода бытовой химии с целью продажи его корпорации «Проктэр энд Гэмбл», мечтавшей об этом предприятии. «Голдмэн Сакс», в частности, очень настаивал, чтобы приватизация шла медленно и по индивидуальным схемам. А также на том, что каждую сделку надо готовить тщательно, чтобы получить хорошие результаты. Собственно, к этому мы и пришли сейчас. Но только сейчас, когда задача ускорения приватизации уже не стоит. Тогда ситуация была совершенно иной. Мы понимали, что в России существуют мощнейшие политические силы, которые, подхватывая лозунг медленной, но «качественной» приватизации, будут делать все, чтобы остановить ее совсем или использовать в сугубо клановых, узкокорыстных интересах.
Наши противники находили кучу аргументов против быстрой, бесплатной массовой приватизации. Если еще вчера нас призывали отдать фабрики рабочим, не понимая при этом последствий для экономики страны, то теперь нам говорили:
– Продажа акций предприятий за деньги – это единственный экономически обоснованный путь, это дополнительные средства в бюджет, это появление эффективного собственника.
Слова были вроде и правильные, но я думаю, что главная цель той полемики была другой: затормозить приватизацию любой ценой! Наши оппоненты понимали: после того как механизм массовой приватизации будет раскручен, остановить его окажется невозможным.
У нас же голова болела о другом. Мы видели: действовавшая программа приватизации противопоставляла интересы менеджеров и работников предприятий интересам всего остального населения. А нас еще и подталкивали к тому, чтобы усугубить этот разрыв! С этим нельзя было согласиться. Да и рассуждения о том, что денежная приватизация окажется намного выигрышнее для экономики, представлялись нам совсем не бесспорными.
Изучили мы, например, опыт польской приватизации. Там начали продавать собственность на денежных аукционах. И что же? отсутствия иностранных и внутренних инвестиций продажа за деньги двигалась черепашьими темпами и приносила бюджету не такие уж большие деньги. За первые два года реализации программы (с середины 1990 года до середины 1992 года) удалось продать контрольные пакеты акции только тридцати двух крупных и средних предприятий. Это принесло в бюджет всего 160 миллионов долларов – намного меньше запланированного.
Ну и что, польский опыт перенимать? А ведь нам надо было приватизировать 25 тысяч крупных и средних предприятий. Даже если бы удавалось пропускать через денежные аукционы не по 15, а по 150 предприятий в год, приватизация в России длилась бы больше полутора столетий! Рассчитывать на серьезное пополнение бюджета и на крупные инвестиции тоже особенно не приходилась. Иностранный капитал не пошел бы в 1992 году в Россию: очень уж низка была тогда инвестиционная привлекательность нашей экономики. Отечественный же капитал в то время обладал очень небольшими ресурсами и не мог полноценно участвовать в коммерческих продажах.
Более демократичной показалась нам чешская модель приватизации. Там, по крайней мере, каждый гражданин мог получить приватизационные чеки и свободно принять участие в аукционе. Однако копировать целиком и полностью эту модель массовой приватизации мы тоже не могли. Чехословакия – страна маленькая, и вместо многих чековых аукционов у них проводился , на котором продавались одновременно акции всех предприятий. Система была жутко централизованной. Представьте себе: из одного места нужно было собирать все заявки на все предприятия сразу (общим числом около 200) и затем находить такие цены, по которым эти предприятия можно все одновременно продать. Понятно, что такая система для России не подходит: невозможно из Москвы продать 25 тысяч предприятий. Но вот сама идея использования приватизационных чеков на специальных чековых аукционах нас заинтересовала. Впрочем, нам сразу было понятно, что и сами российские чеки, и правила их хождения должны существенно отличаться от чешского варианта. Например, в Чехии каждый гражданин страны получал целую книжку, в которой было несколько чеков. Принимая участие в аукционе, можно было подать заявку сразу на акции нескольких предприятий – с каждым чеком в отдельности. Нам показалось, что это излишне сложно, особенно в стране со населением.
И еще нам не понравилось, что в Чехии приватизационный чек нельзя было продавать за деньги. Воспользоваться им можно было только по прямому назначению. А если людям акции совершенно ни к чему, не хотят они с ними возиться? Нам представлялось, что более демократичным будет вариант, при котором чек можно продать, чтобы выручить за него хоть деньги. Кроме того, такая система позволяла с самого начала формировать крупные заявки на чековых аукционах.
Кстати, в последующем жизнь доказала, что мы были правы. Многие коммерческие структуры занимались чековой приватизацией именно таким образом: скупали чеки, подавали большие заявки и покупали целые предприятия уже на чековых аукционах. Нельзя, конечно, говорить, что таким образом сразу же формировался эффективный собственник. Но это был очень серьезный шаг в этом направлении.
Одним словом, после изучения мирового опыта приватизации мы подготовили свою программу. Можно сказать, что в она оказалась несколько ближе к чешскому варианту, чем к польскому, но, в целом, была абсолютно самостоятельной и оригинальной, чисто российской. Главная идея массовой приватизации заключалась в том, что все граждане страны должны получить льготный (бесплатный) доступ к собственности. Под эту идею выстраивался и механизм массовой приватизации.
Всем гражданам, включая детей, за плату в 25 рублей предлагалось получить приватизационные чеки номинальной стоимостью в 10 000 рублей. Каждый гражданин имел право продать свой чек без ограничений; участвовать в чековых аукционах, где чеки обменивались на акции приватизированных предприятий; вложить его в чековые инвестиционные фонды. Рабочие приватизируемых предприятий, кроме того, могли использовать чек для покупки акций своего предприятия в ходе закрытой подписки.
Система приватизационных чеков была введена указом Президента в августе 1992 года. Чеки выдавались с октября по февраль. 144 миллиона граждан России, почти 97 процентов всего населения, получили чеки. После этого переход к частной собственности в России уже трудно было остановить. Если бесплатную массовую приватизацию можно назвать компромиссом с большинством населения страны, то этот компромисс, несомненно, стал самым важным политическим и экономическим решением в ходе российской приватизации.
Отдать Москву – не значит проиграть
С самого начала проведения приватизации мы готовились к политическим атакам оппонентов. И жизнь каждый день снова и снова доказывала нам, что приватизация в России – это не только, а может, даже и не столько экономическое мероприятие, сколько жесточайшее политическое сражение.
Конечно, склонив на сторону приватизации директоров и основные массы населения, мы по большому счету могли бы праздновать победу. Однако мы понимали, что ликовать рано. Приватизацию атаковали с самых разных сторон, и у меня осталось ощущение накатывающихся одна за другой волн таких атак. После мощного наката директората в 1992 году запомнился тяжелый 1993 год, когда приватизацию усиленно атаковал Хасбулатов со своим Верховным Советом. Серьезное сопротивление приватизации оказывали и достаточно влиятельные политические группы, прежде всего региональные лидеры и руководители министерств и ведомств. И те, и другие понимали, что приватизация подорвет их контроль над предприятиями, над собственностью, и не хотели сдаваться без боя.
Дискуссия Лужкова с Чубайсом по поводу московской приватизации не исключение. Терять контроль над предприятиями города московскому правительству не хотелось. Хотя дело не только в этом. Лужков вообще последовательно проводил свою политическую линию, критикуя реформы федерального правительства и отстаивая особый, «московский» вариант реформ. Я порой думаю, что если бы Чубайс предлагал проводить приватизацию за деньги, Лужков бы потребовал бесплатной раздачи имущества. Поэтому считаю, что Чубайс поступил мудро, как Кутузов: он отдал Москву, но выиграл войну.
Прямой резон воевать с приватизацией был и у руководителей министерств и ведомств: акционирование серьезно подрывало их власть. Ведь в 1992 – 1994 годах через акционирование прошли свыше 20 тысяч предприятий, на которых работало свыше 2/3 промышленных рабочих. А значит, они уже не нуждались в опеке главков, трестов, управлений, министерств: собственность сплошь и рядом переходила под управление советов директоров.
Сопротивление отраслевики вели в основном на двух фронтах. , они прилагали массу усилий, запретить приватизацию, либо закрепить в государственной собственности пакеты акций как можно большего числа предприятий. , они пытались провести акционирование , , путем создания подконтрольных им холдингов.
Вопрос о том, что следует приватизировать, стоял очень остро с самого начала работы над программой приватизации. Уже тогда было ясно, что ряд секторов нужно выводить из общей схемы и приватизировать по индивидуальным планам (например, ТЭК, телекоммуникации ). Составлялся и список не подлежащего приватизации имущества. В этот список с одобрения правительства вошли, в частности, железнодорожный транспорт, аэрокосмическая промышленность, учреждения здравоохранения и образования. Однако список постоянно уточнялся. Каждое отраслевое министерство настаивало на том, что именно в их отрасли нельзя проводить приватизацию. Мотивы были традиционными: стратегическая важность, национальные интересы, оборона, высокие технологии… Или даже контроль за идеологией! Так появился запрет на приватизацию предприятий полиграфической промышленности.
Мы же старались распространить приватизацию на возможно большее число предприятий. Весь мировой опыт показывал, что в подавляющем большинстве отраслей промышленности государственная собственность крайне неэффективна, но многие страны пришли к этому выводу сравнительно недавно – в годы. В это время в Великобритании, например, началась приватизация сложных отраслей – энергетики, телекоммуникаций, авиатранспорта. Наша программа предусматривала начало приватизации сразу же с широкого спектра отраслей. Хотя и по специальным схемам, но должны были приватизироваться телекоммуникации, электроэнергетика, авиаперевозки, чего до сих пор никак не могут сделать многие европейские страны.
Немало сил уходило и на борьбу с холдингами. Была тогда в российском правительстве такая фигура – министр промышленности Александр Титкин. Так вот он предлагал очень привлекательную для наших чиновников модель приватизации: вначале все предприятия акционируем, после чего все акции сложим в большие группы. И чтобы министерства ими управляли.
По такой схеме получалась не приватизация, а «холдингизация»: государство сохраняло свой контроль над предприятиями. Мы были уверены: в большинстве случаев холдинги должны образовываться естественным путем, на рынке (как это происходит сейчас), а не за счет государства. Ведь было же совершенно понятно: сегодня чиновники создают свой холдинг, а завтра самыми различными способами будут пытаться использовать казну для его содержания.
Конечно, в отдельных случаях создание холдингов было экономически оправданным. Скажем, нефтяная промышленность шла по этому пути: создавались нефтяные компании, которые владели нефтедобывающими, нефтеперерабатывающими, оптовыми предприятиями. И так действительно получалось более логично. Но подобного рода компании были скорее исключением. Как правило, руководители министерств и ведомств пытались создать такие холдинги, куда просто в кучу сваливались многочисленные предприятия.
Был один вопрос в полемике с нашими оппонентами, по которому мы не соглашались идти ни на какие компромиссы, считая его крайне принципиальным: многие руководители министерств и ведомств, а также представители директората настаивали на том, чтобы законом было разрешено создавать закрытые акционерные общества. В таких обществах каждый акционер, решивший продать свои акции, должен получить на это согласие всех других акционеров.
Понятно, что директора хотели контролировать процесс перераспределения собственности, ни в какую не желая допускать к «своим» предприятиям чужаков. Ведь те могли бы установить контроль за деятельностью самих директоров, а там, глядишь, и вообще попросить их из руководящих кресел. Поэтому идея закрытых акционерных обществ навязывалась нам с особым упорством.
Но мы решили не уступать, понимая, что и так пошли на крупный компромисс с директорами и работниками предприятий, отдав им значительную часть собственности. Да, в итоге мы быстро решали задачу отделения предприятий от государства, но существенно тормозили появление эффективного собственника. Можно сказать, жертвовали качеством ради скорости. Но делали мы это сознательно, имея в виду, что в дальнейшем рынок все расставит по местам и отыщет эффективного собственника. И вот теперь нам навязывали вариант, который начисто исключал саму возможность появления такого рынка: если акции нельзя свободно продавать и покупать, какой же может быть рынок?
Мы понимали, что создание в массовом порядке закрытых компаний привело бы к особо тяжелым последствиям. С одной стороны, многие потенциальные покупатели акций опасались бы вкладывать деньги, так как впоследствии были бы лишены возможности продавать свои акции без согласия других акционеров. С другой – директора и рабочие, получившие акции на льготных условиях, навсегда сохранили бы свой контроль над предприятием. Это во многих случаях создало бы непреодолимый барьер для появления эффективного собственника.
Одним словом, если бы не удалось отстоять акционерные общества открытого типа, пришлось бы констатировать: приватизация заведена в тупик, лучше бы такую приватизацию вообще не затевать.
Свою позицию мы отстояли. После целого ряда вынужденных компромиссов можно было облегченно вздохнуть: путь для формирования эффективного собственника открыт, пусть даже двигаться по нему придется небыстро.
И все же читатель вправе спросить: а стоило ли вообще проводить приватизацию, если требовалось идти на такие компромиссы? Может быть, лучше было бы вообще от нее отказаться? Уверен, что нет. , даже при всех уступках директорам и рабочим приватизация позволила сделать огромный, гигантский шаг вперед к формированию эффективной системы частной собственности. Конечно, после 75 лет господства тоталитарного экономического строя эффективный собственник не мог появиться в одночасье. Но приватизация запустила в действие мощнейшие экономические процессы, которые обеспечивают движение в этом направлении.
, идя на компромиссы и добиваясь политической поддержки приватизации, мы тем самым обеспечивали поддержку реформам в целом. Думаю, что если бы не приватизация, то и весной 1992 года, и в ходе осеннего кризиса 1993 года, когда стоял вопрос о продолжении экономических и политических преобразований в нашей стране, баланс политических сил мог бы оказаться не в пользу реформ.
Оглядываясь сегодня назад, мы можем с полным основанием говорить: отделение экономики от государства в конце XX века – это первое масштабное событие в истории России, осуществленное не путем насилия и диктата, а в результате проведения политики политических компромиссов. Вспоминая сплошь и рядом кровавую историю государства российского, остается только удивляться, что перераспределение собственности удалось осуществить бескровно и ненасильственно.
Источник: Бойко М. Как протащить верблюда сквозь игольное ушко // Приватизация по-российски / Под ред. А.Б. Чубайса. М.: Вагриус, 2000.
Как протащить
03:11 30.08.2023 (обновлено: 10:59 30.08.2023)
https://ria.ru/20230830/bagazh-1892973371.html
Стюардесса рассказала, как бесплатно пронести в самолет больше вещей
Стюардесса рассказала, как бесплатно пронести в самолет больше вещей — РИА Новости, 30.08.2023
Стюардесса рассказала, как бесплатно пронести в самолет больше вещей
Бывшая стюардесса авиакомпании Emirates рассказала, как пронести на борт дополнительную сумку без оплаты, сообщает The Sun. РИА Новости, 30.08.2023
2023-08-30T03:11
2023-08-30T03:11
2023-08-30T10:59
новости — туризм
МОСКВА, 30 авг – РИА Новости. Бывшая стюардесса авиакомпании Emirates рассказала, как пронести на борт дополнительную сумку без оплаты, сообщает The Sun. Если в чемодан и ручную кладь все вещи уложить не удалось, Камила Якубьякова советует взять с собой наволочку от дорожной подушки. В ней можно разместить часть вещей.При этом подушка считается предметом, который можно пронести на борт сверх разрешенной нормы багажа. Обычно пассажиры заходят в салон, разместив ее на шее.Бортпроводники не возражают, чтобы пассажиры брали в салон подушку для сна, она не вызывает вопросов и позволяет заметно увеличить количество перевозимой одежды и с комфортом поспать во время полета.
Русский [ править ]
Приставка: про-; корень: -тащ-; суффикс: -и; глагольное окончание: -ть [Тихонов, 1996] .
Произношение [ править ]
- МФА: [ prətɐˈɕːitʲ ]
Семантические свойства [ править ]
Значение [ править ]
- волоча, таща, пронести до какого-либо места или мимо чего-либо ◆ Отсутствует пример употребления (см. рекомендации ).
- пронести, продвинуть сквозь что-либо, между чем-либо ◆ Отсутствует пример употребления (см. рекомендации ).
- провести, заставить принять или согласиться на что-либо ◆ Отсутствует пример употребления (см. рекомендации ).
Синонимы [ править ]
Антонимы [ править ]
Гиперонимы [ править ]
Гипонимы [ править ]
Родственные слова [ править ]
Ближайшее родство |