Здравствуйте, 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 можно установить.
К нему же можно прикрутить и микрософтовский компилер.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Кодт, Вы писали:
К>Я имел в виду — не написать собственный язык и парсер для него, а просто сделать генерилку кода. К>Пусть в роли DSL будут выступать, например, вызовы питоньих или пхпшных функций.
Для питона кстати есть интересная вещь http://nedbatchelder.com/code/cog/
позволяет оформлять такие мини DSL как комментарии прямо в C++ исходниках.
Здравствуйте, FR, Вы писали:
FR>Для питона кстати есть интересная вещь http://nedbatchelder.com/code/cog/ FR>позволяет оформлять такие мини DSL как комментарии прямо в C++ исходниках.
Много раз всплывала точно такая же идея (inplace generator + маркеры output для обновления (ну а как ещё?)).
Хорошо что есть уже готовая тулза, и судя по возрасту — достаточно зрелая
P.S. Автогенерация — это достаточно огромный и опасный молот. Выдавать его нужно строго по рецепту, так как вызывает привыкание и галлюцинации — все проблемы принимают форму гвоздей, люди начинают забывать элементарные языковые конструкции. Я такого треша насмотрелся