Здравствуйте, Кодт, Вы писали:
К>Я имел в виду — не написать собственный язык и парсер для него, а просто сделать генерилку кода. К>Пусть в роли DSL будут выступать, например, вызовы питоньих или пхпшных функций.
Для питона кстати есть интересная вещь http://nedbatchelder.com/code/cog/
позволяет оформлять такие мини DSL как комментарии прямо в C++ исходниках.
CEM>вроде бы ещё можно как-то это всё на шаблонах сделать, нет? Чтоб в зависимости от параметров часть кода не генерилась?
Использовать шаблоны для оптимизации можно, и получается даже хорошо. По крайней мере код внутри функции будет максимально похож на вариант до преобразования.
Правда придётся чуть изменить вызов функции, но и там изменения малы.
Ну и правильно советуют, что переписывать стоит только после того, как об этом тебе сообщил профайлер.
Но я бы сначала ещё проверил, что делает твой компилятор с исходным текстом. Например, gcc, если ему указать уровень оптимизации -O3, самостоятельно разбивает твой исходный цикл с условиями bA…bD на несколько однородных циклов. То есть он сначала проверяет все условия, и затем переходит к нужному циклу, внутри которого уже никаких проверок не делается (и ненужный код из которых уже удалён). То есть компилятор оказался достаточно умным, чтобы сразу же выполнить твоё желание (и не нужно никаких макросов, шаблонов или дублирования исходного кода).
Здравствуйте, Vzhyk, Вы писали:
>> Зачем что? V>Зачем ты "на шестой студии сидишь"? V>У нее же уже лет как 10 не осталось ни одного достоинства, кроме V>глючности, неподдерживаемости современного С++ и замедления разработки.
Здравствуйте, FR, Вы писали:
FR>Для питона кстати есть интересная вещь http://nedbatchelder.com/code/cog/ FR>позволяет оформлять такие мини DSL как комментарии прямо в C++ исходниках.
Много раз всплывала точно такая же идея (inplace generator + маркеры output для обновления (ну а как ещё?)).
Хорошо что есть уже готовая тулза, и судя по возрасту — достаточно зрелая
P.S. Автогенерация — это достаточно огромный и опасный молот. Выдавать его нужно строго по рецепту, так как вызывает привыкание и галлюцинации — все проблемы принимают форму гвоздей, люди начинают забывать элементарные языковые конструкции. Я такого треша насмотрелся
с одной стороны, не хочется делать 1млн проверок, которые по длине кода могут быть порядка длины "полезного" функционала.
с другой стороны плодить кучу функций с почти одинаковым функционалом не хочется из-за неудобства разработки в нескольких местах сразу
есть идея сделать всё на дефайнах, но некоторые функции большие по размеру, всё будет выглядеть кривовато
вроде бы ещё можно как-то это всё на шаблонах сделать, нет? Чтоб в зависимости от параметров часть кода не генерилась?
Здравствуйте, Ops, Вы писали:
Ops>Например, создать лямбду по условиям и звать в цикле. А эта оптимизация вообще нужна, компилятор не умеет? Посмотри, что там в релизе генерируется.
Прошу прощения, лямбда — это кто?
Оптимизация нужна, потому что real-time, и функций таких куча т.е. спасаю производительность по максимуму, как могу... внутренний код наполовину на асме уже написан
Здравствуйте, CEMb, Вы писали:
CEM>с одной стороны, не хочется делать 1млн проверок, которые по длине кода могут быть порядка длины "полезного" функционала. CEM>с другой стороны плодить кучу функций с почти одинаковым функционалом не хочется из-за неудобства разработки в нескольких местах сразу CEM>есть идея сделать всё на дефайнах, но некоторые функции большие по размеру, всё будет выглядеть кривовато CEM>вроде бы ещё можно как-то это всё на шаблонах сделать, нет? Чтоб в зависимости от параметров часть кода не генерилась?
Можно и на дефайнах.
По сути, нужно выполнить такую трансформацию кода
По-моему, вполне нормальное, "eye driven", сопровождаемое решение.
Более того, можно чуток допилить, чтобы выбирать между for-if и if-for
#define REPEAT for(.....)
// присваиваем этот дефайн в ОДИН из следующих#define REPEAT_HEAD
#define REPEAT_BODY REPEAT
REPEAT_HEAD {
if (aaaaa) REPEAT_BODY { AAAAA }
else if(bbbbb) REPEAT_BODY { BBBBB }
else REPEAT_BODY { CCCCC }
}
#undef REPEAT_HEAD
#undef REPEAT_BODY
#undef REPEAT
Та же фигня с лямбдами может пойти по двум путям.
1) завернуть каждую ветку в лямбду, условным оператором выбрать одну из них и скормить единственному for.
2) завернуть в лямбду заголовок цикла — то есть, тот же #define REPEAT, только без дефайнов
Оба способа плохи тем, что получится косвенный вызов. А если лямбда будет приведена к std::function, то это не просто вызов по указателю на функцию, а довольно жирный косвенный вызов.
Здравствуйте, Кодт, Вы писали:
Ops>>Прошу прощения, думал плюсы К>Таки плюсы, ибо "вроде бы ещё можно как-то это всё на шаблонах сделать, нет?"
Тогда вопрос про лямбды мне непонятен Они же фактически задолго до выхода C++11 в компиляторах появились, сложно не заметить. Да и стандарту уже второй год идет.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>>>Прошу прощения, думал плюсы К>>Таки плюсы, ибо "вроде бы ещё можно как-то это всё на шаблонах сделать, нет?" Ops>Тогда вопрос про лямбды мне непонятен Они же фактически задолго до выхода C++11 в компиляторах появились, сложно не заметить. Да и стандарту уже второй год идет.
Ну я не заметил я на шестой студии сижу, она ругается на функции внутри функций
фигзнает... надо попробовать... но код на глаз неприятный... и обратные слеши тоже не радуют
и мои функции по-больше размером, и число переменных там переменное
Если компилятор не может это оптимизировать, то дальнейшая оптимизация по скорости ведет к увеличению количества исходного кода. Если хочется использовать общий код во всех ифах, придется повторить структуру ифов (статик ифов) внутри этого общего метода. То есть при изменении логики придется менять в 2 и более местах.
On 28.03.2013 11:34, CEMb wrote:
> Ну я не заметил я на шестой студии сижу, она ругается на функции внутри > функций
Можно нескромный вопрос: "А зачем?"
Здравствуйте, Vzhyk, Вы писали:
>> Ну я не заметил я на шестой студии сижу, она ругается на функции внутри >> функций V>Можно нескромный вопрос: "А зачем?"
On 28.03.2013 12:03, CEMb wrote:
> Зачем что?
Зачем ты "на шестой студии сидишь"?
У нее же уже лет как 10 не осталось ни одного достоинства, кроме
глючности, неподдерживаемости современного С++ и замедления разработки.
Здравствуйте, watch-maker, Вы писали:
WM>Использовать шаблоны для оптимизации можно, и получается даже хорошо. По крайней мере код внутри функции будет максимально похож на вариант до преобразования. WM>
Правда придётся чуть изменить вызов функции, но и там изменения малы.
А, это же с учётом того, что оптимизатор порежет все констнтые условия?!! Блин, чё я сам не догадался до этого...
WM>Ну и правильно советуют, что переписывать стоит только после того, как об этом тебе сообщил профайлер.
да, надо всё-таки заиспользовать профайлер...
WM>Но я бы сначала ещё проверил, что делает твой компилятор с исходным текстом. Например, gcc, если ему указать уровень оптимизации -O3, самостоятельно разбивает твой исходный цикл с условиями bA…bD на несколько однородных циклов. То есть он сначала проверяет все условия, и затем переходит к нужному циклу, внутри которого уже никаких проверок не делается (и ненужный код из которых уже удалён). То есть компилятор оказался достаточно умным, чтобы сразу же выполнить твоё желание (и не нужно никаких макросов, шаблонов или дублирования исходного кода).
Опаньки, как, оказывается, далеко техника ушла А я тут сижу (у меня микрософтовский компилятор, VС6.0, VС2010), вручную код разбираю... асм-вставки в дефайнах пишу... ну, кстати, на 6-й студии это часто сильно помогало...
Здравствуйте, CEMb, Вы писали:
CEM>У меня вот такая мутохрень получилась:
<>
Это поистине ужасно. Сразу по многим пунктам.
Если это в продакшене — то можно подумать, как сделать лучше. Если же это дистиллированный код, чтобы написать сюда, "по мотивам" реального, — то покажи настоящий код, а не это издевательство над глазами.
Ну а пока предположу, что истина посередине, поэтому
1. Давай нормальные имена аргументам.
2. Не бойся, что компилятор оставит if(false) break и if(true) как есть в ассемблерном коде. Не оставит. Поэтому вместо fnctrl там появятся выражения условий.
Таким образом, каркас функции выглядит так:
Но я всё равно крепко подумал бы, насколько нужно иметь такой мега-макрос.
Иногда удобнее сделать пачку макросов, из которых собирается код. Как, например, MFC-шные BEGIN_MESSAGE_MAP()/MESSAGE_HANDLER()/END_MESSAGE_MAP().
Иногда даже удобнее написать собственный генератор сишного кода. Вот, например, lex и bison
Ну во первых оптимизаторы современных компиляторов С++ сгенерируют код настолько близко к оптимальному, что если ты задействуешь хоть первый, хоть второй варианты, результирующий код будет очень похожим. А во вторых, почему ты думаешь, что тормоза именно в этих местах?
Здравствуйте, CEMb, Вы писали:
CEM>А, это же с учётом того, что оптимизатор порежет все констнтые условия?!!
Ага, ведь это одна из базовых техник оптимизации и от вменяемого компилятора вполне естественно ожидать её применения.
WM>>Но я бы сначала ещё проверил, что делает твой компилятор с исходным текстом. Например, gcc, если ему указать уровень оптимизации -O3, самостоятельно разбивает твой исходный цикл с условиями bA…bD на несколько однородных циклов. То есть он сначала проверяет все условия, и затем переходит к нужному циклу, внутри которого уже никаких проверок не делается (и ненужный код из которых уже удалён). То есть компилятор оказался достаточно умным, чтобы сразу же выполнить твоё желание (и не нужно никаких макросов, шаблонов или дублирования исходного кода).
CEM>Опаньки, как, оказывается, далеко техника ушла :) А я тут сижу (у меня микрософтовский компилятор, VС6.0, VС2010),
Тогда придётся изменять исходный код. Самостоятельно делать loop unswitching эти два компилятора не умеют.
Здравствуйте, Кодт, Вы писали:
К>Но я всё равно крепко подумал бы, насколько нужно иметь такой мега-макрос. К>Иногда удобнее сделать пачку макросов, из которых собирается код. Как, например, MFC-шные BEGIN_MESSAGE_MAP()/MESSAGE_HANDLER()/END_MESSAGE_MAP().
Да я вот тоже уже посмотрел на первые варианты, крепко подумал и решил макромакрос не делать
К>Иногда даже удобнее написать собственный генератор сишного кода. Вот, например, lex и bison
Не, от этой идеи я что-то тоже отказался
Здравствуйте, ArtDenis, Вы писали:
AD>А во вторых, почему ты думаешь, что тормоза именно в этих местах?
Просто давно работаю с этим семейством алгоритмов, в процессе разных оптимизаций выяснилось.
В данном случае тормозов _пока_ нет, потому что задачи пока маленькие, относительно. Но они будут расти на порядки, и так как тут огромное количество конвейерной арифметики, её количество со временем просто начнёт задавливать вычислительные ресурсы. Хочется как можно сильнее минимизировать расчёты. Поэтому придумываю вот такие разные выкрутасы
Здравствуйте, CEMb, Вы писали:
К>>Иногда даже удобнее написать собственный генератор сишного кода. Вот, например, lex и bison CEM>Не, от этой идеи я что-то тоже отказался
Я имел в виду — не написать собственный язык и парсер для него, а просто сделать генерилку кода.
Пусть в роли DSL будут выступать, например, вызовы питоньих или пхпшных функций.
Ну, скажем,
def make_scanner(name,args,rettype,on_begin,loop,on_iteration,branches,on_end,retval) :
lines = []
lines += [
'%s %s(%s) {' % (rettype,name,args),
' %s' % on_begin
]
for cond,branch in branches :
lines += [
' if(%s) {' % (cond if cond else'true') # None - это дефолтная ветка будет.' for(%s) {' % loop,
' %s' % on_iteration,
' %s' % branch,
' }',
' } else'# продолжение следует...
]
lines += [
' ;', # закрываем последнее else' %s' % on_end,
' return %s;' % retval,
'}'
]
return'\n'.join(lines)
f = open('generated.cpp', 'w')
print>>f, '#include <cstdio>'print>>f, make_scanner(
name = 'foo', # имя функции
args = 'int x, int y, int z', # аргументы
rettype = 'void',
on_begin = 'print("starting...");',
loop = 'int i=0; i!=100; ++i', # шапка цикла
on_iteration = 'printf("iteration %d\\n", i);', # то, что входит в каждую итерацию безусловно
branches = [ # список веток в цикле
('x<0', 'printf(" %d ", i*-x);'),
('x>0', 'printf(" %d ", i*+x);'),
(None, 'printf(" 0 ");')
],
on_end = 'printf("done.");',
retval = ''# потому что void
)
1. Как уже говорилось компилятор вполне может вынести неизменяемые переменные и условия за цикл.
2. если в разных бранчах производятся различные действия , то практика помещять их в отдельные функции очень неплоха. (FOREACH кстати помогает и <algorithm>)
3. обычно вычисления можно свести к небольшим наборам примитивов и сложные циклы не гонять. (а стандартные еще и хорошо оптимизированны dot_product LUT и т.п.)
4. если вы не пользуетесь профайлером , то начать надо с него.
Здравствуйте, CEMb, Вы писали:
CEM>Оптимизация нужна, потому что real-time, и функций таких куча т.е. спасаю производительность по максимуму, как могу... внутренний код наполовину на асме уже написан
Киньте пару примеров, возможно будет интересно глянуть
Здравствуйте, Andrew S, Вы писали:
AS>Ответы на исходный вопрос: AS>1. Макросы либо шаблон стратегии, 6-ка это съест. AS>2. Перфоманс аналайзеры: xperf, vTune 9.1(с).
AQtime 6 рульный профайлер подходит как для .net так и для нативных программ
AS>>Ответы на исходный вопрос: AS>>1. Макросы либо шаблон стратегии, 6-ка это съест. AS>>2. Перфоманс аналайзеры: xperf, vTune 9.1(с).
J>AQtime 6 рульный профайлер подходит как для .net так и для нативных программ
Посмотрел видео, доступные на сайте разработчика. Если честно, не впечатлился:
1. Непонятно, есть ли необходимость в специальной сборке — на видео все сборки в дебаге (!!!) — они профилируют дебаг, да. Если есть — в топку.
2. Убогие средства анализа. Попробуйте сравнить со стандартным xperfview или с тем, что доступно вместе с ADK — каким образом отслеживать вейты, непонятно, как отсматривать доступ к диску/FS/сетке/реестру со стеками и т.п. — все то, без чего профилирование чего то более сложного, чем числодробилки, просто невозможно. Отслеживать передачу управления между потоками тоже непонятно как. Callgraph — пародия на то, что предоставляет vTune.
3. Тюнинг кода. vTune предоставляет сильно больше информации по оптимизации конечного кода, чем то, что мне показали на видео — там и промахи по кешам, и выравнивания и прочее. Где все это в "рульном" профайлере?
4. Профилирование на удаленной машине. xperf по сути часть OS, и возможность просто попросить кастомера снять etw логи и прислать для анализа стОит очень многого. И да, xperf — бесплатен.
5. Для etw можно написать своего провайдера и получить сильно больше, чем самплинг или стандартные провайдеры. В сочетании с (4) это дает почти полный контроль над производительностью приложения.
В целом — по представленным на сайте разработчика видео это средство начального уровня, пригодное для профилирования несложных псевдо-многопоточных приложений. Но сравнивать ни с vTune, ни с xperf это не стОит.
Из интересных возможностей — отслеживаение утечек ресурсов и отслеживание референсов на ком объекты. Непонятно, правда, зачем это надо в наш век С++ и смарт поинтеров — утечек памяти в современном С++ коде (не алгоритмических, а багов с управлением ресурсами) я уже давно не видел, но и вреда от такой возможности вроде бы нет.
Повторюсь, полноценный набор инструментов профилирования — это:
1. vTune 9.1с — инструментирование — тонкий анализ узких мест кода, удобный callgraph. Семплинг на событиях для оптимизации работы с процессором.
2. xperf — анализ многопоточных взаимодействий, работы с системными ресурсами, "грубый" самплинг.
Инструменты дополняют друг-друга, по отдельности они не обеспечивают полноценного профилирования. И, да — версия vtune имеет значение, новый не имеет инструментирования и не имеет особых преймуществ перед бесплатным xperf.
Здравствуйте, CEMb, Вы писали:
CEM>Здравствуйте, Vzhyk, Вы писали:
>>> Зачем что? V>>Зачем ты "на шестой студии сидишь"? V>>У нее же уже лет как 10 не осталось ни одного достоинства, кроме V>>глючности, неподдерживаемости современного С++ и замедления разработки.
CEM>У неё класс-визард удобнее, чем у 10-й
Перейди на 8-ю...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, CEMb, Вы писали:
CEM>Здравствуйте, Ops, Вы писали:
Ops>>Например, создать лямбду по условиям и звать в цикле.
CEM>А лямбды с какой версии сей поддерживаются?
стандарт С++11
А в отдельных компиляторах — и раньше было.
Особо обрати внимание на gcc — там много стандарта С++11 реализовано
GCC — например в составе QtCreator можно установить.
К нему же можно прикрутить и микрософтовский компилер.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!