Обновить
88
Евгений Охотников@eao197

Велосипедостроитель, программист-камикадзе

2,1
Рейтинг
86
Подписчики
Отправить сообщение

так вас производительность волнует или разбухание?

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

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

Пусть будут хотя бы какие-то цифры. Но их нет вообще. Этого, собственно, в статье и не хватило.

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

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

были обозначены проблемы и пути их решения.

С этим как раз все понятно.

почему бы не поговорить о сути статьи?

Потому что лично для меня суть не раскрыта полностью без обсуждения накладных расходов. Ваш основной тезис – trace points можно расставлять в коде по надобности и не сильно заботиться о том, что они негативно сказываются на производительности. Зато в любой момент их можно активировать и увидеть то, что поможет найти проблему. С этим OK ровно до тех пор, пока накладные расходы реально низкие. А вот так это или нет… Предлагаете праздному читателю самому скачать вашу библиотеку и устроить бенчмарк?

не будет никакого разворачивания параметров

Здесь речь идет о том, что наличие LogmeTPt превращает код простой функции:

void f() {
  LogmeTPt(...);
  bla-bla-bla;
}

во что-то вида:

void f() {
   {
      static Logme::TracePoint tracePoint(__FILE__, __FUNCTION__, __LINE__);
      tracePoint.Hit();
      if (!tracePoint.Registered)
        Logme::Detail::RegisterTracePointOnce(tracePoint);
      if (tracePoint.Enabled && Logme::Instance->Condition())
      {
        static Logme::ContextCache contextCache;
        dispatch(Logme::Instance, contextCache, level, &CH, &SUBSID, __FUNCTION__, __FILE__, __LINE__ __VA_OPT__(, __VA_ARGS__));
      }
    } while (0)}
   bla-bla-bla;
}

и если вы хотите сказать, что все это разбухание функции f() из-за единственного LogmeTPt – это все совершенно бесплатно, то мне остается еще раз повторить: приведите цифры, пожалуйста.

Всё тело then - это один вызов функции.

Полагаю, что вот в этом месте:

  LogmeTPt(
    "begin header parsing: client=%s bytes=%zu"
    , connection->GetIp().c_str()
    , buffer.Size()
  );

Он все-таки не один. Тут есть еще вызовы GetIp(), c_str(), Size().

И еще неизвестно во что разворачивается сам LogmeTPt.

Upd. А разворачивается LogmeTPt отнюдь не совсем в безобидную конструкцию. Там декларация статической переменной, вызов Hit для нее (всегда), проверка флага Registered… И только потом собственно логирование, если оно разрешено.

Слишком много пустых разговоров там, где достаточно было бы сухих цифр. Вы у себя в статье привели в пример код метода ParseHeaders. Вот и озвучили бы замеры – без trace points вообще и с отключенными trace points.

Там дело не только в if-е. А в том, что код с trace point-ами будет выглядеть как куча if-ов с некоторым (подозреваю) не сильно маленьким телом then. Что раздувает код выполняемой функции и это может сказаться общей скорости работы. Поэтому и хотелось бы видеть в статье бенчмарки.

в данном случае я видел свою задачу в том чтобы обсудить проблему как таковую

Ну вот по крайней мере одному читателю этого оказалось недостаточно. А может и не одному, просто одному стало не лень об этом написать.

Что касается подхода, то на обычном логгинге что-то подобное делается либо посредством иерархических логгеров, либо посредством отдельных объектов-логгеров (с общим бэк-ендом). Тогда логгеры могут включаться-выключаться независимо и это не требует внесения в проект новых типов сущностей.

Мне кажется, что вы не понимаете суть высказанной мной претензии к вашей статье. Я прекрасно понимаю роль этих ваших trace points. Но ваша статья выглядит откровенно неполной без упоминания того, какие накладные расходы эти самые trace points несут. Типа того, что вот эта процедура вообще без trace points в таком-то бенчмарке показывает время N sec, а с trace points – (N sec + 150ms). Или (N sec + 150 sec).

но в этой реализации “спящий” trace point не похож на обычное отключённое логирование. он не строит сообщение, не форматирует данные, не создаёт контекст, не вызывает backend-ы и не захватывает lock-и

В нормальных системах логирования ничего этого нет, если уровень логирования ниже активного сейчас. Фактически, это один if внутри которого идет одно атомарное чтение этого самого активного уровня. А все, что вы перечислили выполняется только внутри then-а.

Не раскрыта тема накладных расходов на “спящие” trace point. Так-то в нагруженных участках кода даже логирование стараются не оставлять (даже не смотря на то, что из этого логирования по факту остается только лишь один if на проверку log-level), а тут подразумевается большое количество trace point-ов в коде. Они же должны оказывать влияние на скорость и тем, что хотя бы один if делается + размер кода растет за счет наличия таких if-ов.

Кстати, после того, как я указал на это, вы стали пытаться разбираться глубже, так что не зря я на это указал!

Вы глубоко заблуждаетесь. Впрочем, как и обычно.

А если язык недостаточно выразителен, то это невозможно

Это понятно. Но тут можно было бы дать какое-то более понятное описание принципа работы зависимых типов либо просто в текстовом виде, либо в виде псевдокода на C++подобном языке (мол если бы в C++ было вот это и вот это, то…), либо можно было бы дать ссылку на какое-то хорошее описание зависимых типов, понятное для чайников, либо… (варианты всегда есть).

Но приведенный вами пример кода на неизвестном мне языке оказался для меня совершенно бесполезным. О чем я вам и говорю.

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

А он и не может, т.к. это всего лишь незаконченный набросок.

тоже на непонятном вам языке?

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

Еще раз повторю для чего мне пришлось сделать свой набросок. Из вашего рассказа я понял (возможно, ошибочно), что зависимые типы заставляют разработчика сделать две вещи:

  1. Отказаться от использования в качестве индексов простых числовых типов (вроде int-ов, size_t и т.д.). Вместо этого вводится специальный тип, который обозначает “гарантированно валидный индекс”, при применении которого дополнительные проверки в run-time уже не нужны.

  2. Реализовать какой-то механизм порождения экземпляров этого типа.

Что я и попытался выразить примитивным и незавершенным наброском на C++. Там обе эти вещи выражены явным образом.

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

Типы не запрещают написать функцию, которая всегда для данных (i, N/2) возвращает valid_index { i - N/2 }. С завтипами такую функцию написать невозможно. Понимаете эту разницу?

Понимаю.

Или вы считаете, что это ерунда и эта разница несущественная?

Считаю, что она существенная и поэтому мне интересно за счет чего эта разница возникает. Но вместо того, чтобы объяснить зависимые типы “на пальцах” вы критикуете мой C++ный набросок и пытаетесь строить предположения о моей воинственности.

Это был бы ответ джаваскриптера вам, конечно.

Здесь остается только спросить “а этот джаваскриптер, который типа мне что-то отвечает, он с вами сейчас в одной комнате?”

Он бы вас устроил, и вы бы согласились, что int перед age как отдельный сигнал компилятору — это несущественные мелочи и докапывание до столба, или таки нет, таки это ключевой момент?

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

Ведь лучше — приходить в комменты об $X и воспевать $X, не так ли?

Если вас интересует мое мнение, то оно такое: вы решили приходить в статьи про C++ чтобы рассказывать какое C++ говно, вам явно кажется, что такое поведение – это хорошая идея, но для меня это выглядит как форма какого-то растройства. Есть это расстройство на самом деле (как обида на потраченные впустую молодые годы) или нет – не важно, я исхожу только от впечатления которые производят ваши комментарии на меня.

Приходить ли в комменты про $X чтобы воспевать $X?

ХЗ, меня этот вопрос не заботит.

Да, экстраполяция прошлого опыта

Такая экстраполяция – это ваши личные предположения. Вы что-то себе предположили, а затем выдали это в качестве оценки для собеседника. Грубо говоря: “сами нафантазировали, сами побежали опровергать”.

Желание не понимать начинает становиться воинственным, ну да ладно.

Когда-то вам показалось, что потратить молодость на изучение С++ – это хорошая идея. Потом вам показалось, что приходить в комментарии к статьям про С++ и рассказывать какое C++ говно – это хорошая идея. Теперь вам кажется, что в моих словах есть что-то воинственное.

Попробую еще раз донести до вас простую мысль: если вы хотите объяснить что-то собеседнику, то хорошо бы это делать на том уровне и на том языке, который понятен вашему собеседнику (а не вам лично). Я вот даже не понял что за язык использован в вашем примере кода – Haskell, Agda или Idris. Соответственно, для меня нет ни вашего примера, ни вашего пояснения.

Я уже подробно написал выше, почему этот перевод так себе.

То, что вы написали, есть не более чем “доколупаться до столба”. Мой пример призван был всего лишь показать, что индекс, который программа может считать безопасным для использования, выражается отдельным типом (а не простым size_t или int-ом, как это сейчас массово встречается в реальном C++ном коде). А производят экземпляры этого типа специальные функции, внутри которых делаются необходимые проверки.

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

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

в этот раз попробую аналогией

Ну и зря. У вас не получилось. Ожидаемо.

это как если бы вы объясняли джаваскриптеру концепцию проверки типов C++, говоря, что предлагается просто писать

Я бы так не объяснял. А вот вы, вполне возможно. С тем же результатом, с которым вы здесь попытались “объяснить” мне подход с зависимыми типами.

Что бездоказательного

Чуть меньше чем все.

что доверяя владение другому лицу, ты больше ничего не можешь гарантировать?

Как будто отправляя рецепт в Conan или в vcpkg вы поступаете как-то иначе.

Внешние ссылки склонны умирать, устаревать и просто бесследно исчезать

Что в рецепте Conan-а, что в порте vcpkg лежат точно такие же внешние ссылки, которые склонны умирать, устаревать и просто бесследно исчезать ©

PS. Предлагаю воздержаться от продолжения этого бесполезного обсуждения ваших глупостей.

Если их не собирать в одном месте, то и гарантий собираемости не обеспечить.

Это слишком сильное и, полагаю, бездоказательное утверждение.

Мы или пилим централизованно и одинаково

О том, к чему это ведет, видно из статьи.

Сам я на Conan давно забил, делаю обновления только на vcpkg. Но и там были случаи, когда принятия PR нужно было ждать неделями.

или оставляем всё как было

Не понимаю такой двоичной логики. Есть еще вариант – комитет таки перестает вредить (шутка) и рожает наконец стандартное описание зависимостей. Тогда все будут описывать зависимости проектов в стандартом виде. Просто не обязательно собирать готовые рецепты в одном месте (как это сейчас происходит с Conan и vcpkg).

Помнится, какой-то подкомитет посвященный тулингу в комитете по стандартизации C++ есть. Результатов пока не видно. Но он есть.

Рецепты хранятся вместе с кодом, registry можно зеркалировать и поднимать свои

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

А если делаешь какую-то программку для себя или собственную библиотеку, то это уже оверкилл, как по мне. Между тем, каких-то зависимостей в Conan-е может не быть (или там какие-то старые версии).

Статья затрагивает сразу несколько важных аспектов и OpenSource здесь только один из. Возможно даже не самый важный.

Позволю себе заострить внимание вот на каком моменте: имхо, системы управления зависимостями для C++ не должны быть централизованными (как это происходит с Conan и vcpkg). Вместо того, чтобы сделать рецепт для условной библиотеки X (которая зависит от Y и Z) и отправить PR на включение этого рецепта в Conan/vcpkg, было бы лучше опубликовать этот рецепт где-то отдельно. Например, в репозитории библиотеки X.

В рецепте для X были бы ссылки на аналогичные рецепты для Y и Z, что-то вроде (синтаксис условный):

"depends": [
  {"name": "Y", "receipe": "https://github.com/y-lib-org/receipes/v1.2.3"},
  {"name": "Z", "receipe": "https://github.com/z-lib-org/receipes/v3.2.1"}
],
...

В проекте, где потребовался бы X, было бы что-то вроде:

"depends": [
  {"name": "X", "receipe": "https://github.com/x-lib-org/receipes/v0.1.1"},
],
...

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

При такой распределенной структуре можно было бы не зависеть от того, что в условный conan-center PR могут принимать неделями. Да и для каких-то библиотек можно собственные рецепты писать и поддерживать (даже если авторы библиотек не хотят потом эти рецепты к себе в апстрим забирать).

Потому что объяснение было механизма

Объяснение было? Простите, если оно было, то оно было расчитано на людей, гораздо более умных и эрудированных, чем я, поэтому оно прошло совершенно мимо меня.

Ну вообще да

Ну вообще нет.

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

Мой код – это всего лишь попытка перевести то, что я (не)понял из ваших объяснений и примера кода на неизвестном мне языке программирования на псевдокод на C++ (который, полагаю, гораздо лучше понятен читателям данной статьи). А именно – вводится тип, который означает “валидный индекс” и работа далее ведется именно через экземпляры этого типа, посему дополнительные проверки при обращении к вектору посредством таких экземпляров уже не нужны.

1
23 ...

Информация

В рейтинге
1 478-й
Откуда
Гомель, Гомельская обл., Беларусь
Зарегистрирован
Активность