Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Подскажите по оптимизации
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
v1vas
Дано: Virtex-6 XC6VLX240T
Центральный модуль, включающий себя UART и подготовку данных.
Есть вычислительные модули, которые коннектятся к центральному, их интерфейс:
Код
(
        clock              : in std_logic;
        reset              : in std_logic;
        
        data_input         : in std_logic_vector(31 downto 0);
        data_flag          : in std_logic;

        done                  : out std_logic;
        data_ready         : out std_logic
)


С точки зрения использования ресурсов в плис влезает около 230 таких модулей + центральный.

При 64 модулях все это хорошо живет на 200Мгц, данная частота и является целью. При 128 модулях синтезатор уже выдаёт максимальную частоту 140MHz, что не устраивает.
Причем, PlanAhead показывает, что критические пути - это линии соединения вычислительных модулей с центральным.
Попробовал добавить регистры в эти линии:
Код
signal reset_corebuf              : std_logic_vector(NCORES - 1 downto 0);
signal data_input_corebuf         : std_logic_vector((NCORES * 32) - 1 downto 0);
signal data_flag_corebuf          : std_logic_vector(NCORES - 1 downto 0);
signal done_corebuf                 : std_logic_vector(NCORES - 1 downto 0);
signal data_ready_corebuf         : std_logic_vector(NCORES - 1 downto 0);

    process (clk)
    begin
        if (rising_edge(clk)) then
            for i in 0 to NCORES - 1 loop
                reset_corebuf(i) <= reset;
                data_input_corebuf((i + 1) * 32 - 1 downto i * 32) <= core_data;
                data_flag_corebuf(i) <= data_core_flag(i);
                
                core_done(i) <= done_corebuf(i);
                data_core_ready(i) <= data_ready_corebuf(i);
            end loop;
        end if;
    end process;

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

Подскажите пожалуйста, что я делаю не так и куда копать)
des00
Цитата(v1vas @ Mar 24 2015, 04:59) *
Подскажите пожалуйста, что я делаю не так и куда копать)

для начала перестать работать в слепую и выложить схему вашей архитектуры(чем полнее тем лучше), на ней будут видны критические места этой архитектуры. только потом искать решение.
Timmy
Цитата(v1vas @ Mar 23 2015, 23:59) *
И вот эти промежуточные сигналы уже законнектил к вычислительным модулям. Лучше не стало, хотя по логике - должно.
Подскажите пожалуйста, что я делаю не так и куда копать)

При ручной репликации регистров на все реплицированные сигналы надо повесить атрибут syn_preserve, иначе синтезатор их может оптимизировать в один регистр, из-за чего у вас, вероятно, и не стало лучше. Кроме того, 230*35 - это 8000 независимых длинных линий, которые будут зря жрать электричество и могут переполнить ресурсы интерконнекта. Лучше создать древовидную структуру, например, 16 регистровых групп к центральному блоку, и 8-16 оконечных устройств на каждую регистровую группу.
iosifk
Цитата(v1vas @ Mar 23 2015, 23:59) *
Дано: Virtex-6 XC6VLX240T
Центральный модуль, включающий себя UART и подготовку данных.

С точки зрения использования ресурсов в плис влезает около 230 таких модулей + центральный.

Подскажите пожалуйста, что я делаю не так и куда копать)

Если не вдаваться в детали, то дело выглядит удивительно...
Есть один медленный UART и не понятно кто делает протокол передачи байтов в хост.
Дальше еще удивительней. 230 модулей должны работать ОДНОВРЕМЕННО??? Тогда сколько же длится "Обработка в модуле", если ее результат передается не понятно по какому протоколу через медленный UART.
Почему-то мне кажется, что если сделать многопоточную обработку одним модулем да еще и на 200Мгц, то он вполне справится за то время, пока UART передает-получает данные в хост. Ну, если уж не один модуль, то десятка вполне хватит...
И при таком подходе обнаружится, что кристалл будет заполнен на 10%...
ASN
v1vas
У Вас в FPGA более 800 BRAM.
Если на выходе каждого модуля UART поставить пакетный буфер из BRAM, то станет возможным "перекачивать" данные во входной пакетный буфер в BRAM центрального модуля.
По идее должно улучшить времянку.
А лучше вообще сделать мультиплексор сигналов древовидным, как предложил уважаемый Timmy, да и вообще очень навороченным: из нескольких модулей в одну BRAM.
Присоединюсь к уважаемым des00 и iosifk, что пока архитектура не очень ясна, трудно что-либо толковое посоветовать.
v1vas
Давайте вдаваться в детали, чтобы все не выглядело так ужасно, как это понял iosifk =)

Есть вычислительный модуль, в нем достаточно легковесная математика. Он единоразово принимает 34 байта стартовых данных и далее на протяжении примерно 5 500 000 000 шагов (1 шаг - 1 такт) эти данные обрабатывает. При частоте 200МГц - это около 30 секунд. В процессе этих 30 секунд никакие данные модулю больше не нужны. По итогам работы модуля мы на выходе получаем один бит: вычислилось ли интересующее нас значение или нет (флаг data_ready в первом интерфейсе, что я написал). Это происходит в среднем только один раз на 300 000 вариантов входных данных, поэтому мне достаточно просто знать для каких данных это произошло, а все остальное я проверяю на хосте. Ну и соответственно есть флаг done, когда все модули закончили - я им бросаю следующую пачку данных, предварительно принятых по UART, а обратно отправляю номер модуля который что-то вычислил, если он есть.

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

Главный модуль: объединяет и контролирует всё это.

Общая структура и порядок работы главного модуля:
1) Проверяем FIFO, в котором скапливаются данные прилетевшие с хоста, для каждых 34 байт оказавшихся там - отправляем их в вычислительный модуль.
2) Когда загрузили все модули - ждем, пока все модули посчитают (у всех done = '1')
3) Если у какого-то модуля data_ready = '1' - кидаем номер этого модуля в FIFO для отправки данных на хост
4) Ресетим модули и идем на пункт один

Вычислительный модуль:
1) Если data_flag = '1', то в data_input лежат валидные данные.
2) Как накопили 34 байта - начали работу.
3) Если вычислилось то, что нужно data_ready <= '1';
4) Как закончили done <= '1';

Изначально вычислительные коннектились к основному прозаично:
Код
MTMainCores:
    for i in 0 to NCORES - 1 generate
    begin
        CoreEntry: CRMain
        GENERIC MAP
        (
            CORE_N => i
        )
        PORT MAP
        (
            clock => clk,
            reset => reset,
            data_input => core_data,
            data_flag => data_core_flag(i),
            done => core_done(i),
            data_ready => data_mt_ready(i)
        );
    end generate MainCores;


Потом добавил регистры, про которые написал в первом сообщении. По совету Timmy добавил им аттрибут "keep":
Код
attribute keep : string;  
attribute keep of reset_corebuf: signal is "true";  
attribute keep of data_input_corebuf: signal is "true";  
attribute keep of data_flag_corebuf: signal is "true";  
attribute keep of done_corebuf: signal is "true";  
attribute keep of data_ready_corebuf: signal is "true";


И на текущий момент имею 48084 timing score для 128 модулей и вот такой критический путь:
Код
Paths for end point Mmux__n4665412_FRB (SLICE_X98Y138.D3), 312 paths
--------------------------------------------------------------------------------
Slack (setup path):     -2.621ns (requirement - (data path - clock path skew + uncertainty))
   Source:               MTMainCores[3].CoreEntry/data_ready_BRB2 (FF)
   Destination:          Mmux__n4665412_FRB (FF)
   Requirement:          5.000ns
   Data Path Delay:      7.486ns (Levels of Logic = 5)
   Clock Path Skew:      -0.100ns (1.521 - 1.621)
   Source Clock:         clk_BUFGP rising at 0.000ns
   Destination Clock:    clk_BUFGP rising at 5.000ns
   Clock Uncertainty:    0.035ns
  
   Clock Uncertainty:          0.035ns  ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE
     Total System Jitter (TSJ):  0.070ns
     Total Input Jitter (TIJ):   0.000ns
     Discrete Jitter (DJ):       0.000ns
     Phase Error (PE):           0.000ns
  
   Maximum Data Path at Slow Process Corner: MTMainCores[3].CoreEntry/data_ready_BRB2 to Mmux__n4665412_FRB
     Location             Delay type         Delay(ns)  Physical Resource
                                                        Logical Resource(s)
     -------------------------------------------------  -------------------
     SLICE_X70Y134.DQ     Tcko                  0.337   MTMainCores[3].CoreEntry/data_ready_BRB2
                                                        MTMainCores[3].CoreEntry/data_ready_BRB2
     SLICE_X70Y132.C1     net (fanout=1)        0.710   MTMainCores[3].CoreEntry/data_ready_BRB2
     SLICE_X70Y132.C      Tilo                  0.068   data_mt_ready<3>
                                                        MTMainCores[3].CoreEntry/data_ready_rstpot
     SLICE_X97Y70.B3      net (fanout=5)        2.967   data_ready_corebuf<3>
     SLICE_X97Y70.B       Tilo                  0.068   data_mt_ready<7>
                                                        Mmux__n466542
     SLICE_X98Y112.D6     net (fanout=1)        1.627   N19372
     SLICE_X98Y112.D      Tilo                  0.068   MTMainCores[21].CoreEntry/SM_STATE_FSM_FFd4_BRB1
                                                        Mmux__n466544
     SLICE_X98Y138.C5     net (fanout=1)        1.158   N19376
     SLICE_X98Y138.C      Tilo                  0.068   Mmux__n4665412_FRB
                                                        N19384
     SLICE_X98Y138.D3     net (fanout=1)        0.345   N19384
     SLICE_X98Y138.CLK    Tas                   0.070   Mmux__n4665412_FRB
                                                        Mmux__n4665412
                                                        Mmux__n4665412_FRB
     -------------------------------------------------  ---------------------------
     Total                                      7.486ns (0.679ns logic, 6.807ns route)
                                                        (9.1% logic, 90.9% route)
des00
Цитата(v1vas @ Mar 25 2015, 01:42) *
Общая структура и порядок работы главного модуля:
1) Проверяем FIFO, в котором скапливаются данные прилетевшие с хоста, для каждых 34 байт оказавшихся там - отправляем их в вычислительный модуль.
2) Когда загрузили все модули - ждем, пока все модули посчитают (у всех done = '1')
3) Если у какого-то модуля data_ready = '1' - кидаем номер этого модуля в FIFO для отправки данных на хост
4) Ресетим модули и идем на пункт один

Вычислительный модуль:
1) Если data_flag = '1', то в data_input лежат валидные данные.
2) Как накопили 34 байта - начали работу.
3) Если вычислилось то, что нужно data_ready <= '1';
4) Как закончили done <= '1';

понятно, майнер делаете. Интерфейс ваших данных 34 байта и интерфейс результата перенесите в домен низкой частоты UART (CDC поставьте в вычислительные движки), саму шину на запись сделайте что-то вроде вишбона, на чтение соберите все с большой сдвиговый регистр и результат на хост. Ну и констрейны правильные натравить. И все заробит.

ЗЫ. схему бы нарисовали себе, все стало бы как на ладони. У меня бойцы в добровольно-принудительном порядке такое делают.
v1vas
Это не майнер, это очень специфичный брут-форс для очень экзотичной задачи) Но архитектурно идеи те же, согласен.

Схему держу в голове, объёма мозга хватает. Но перенесу на бумагу, хорошо, заодно и здесь выложу.

За советы спасибо! Начну воплощать.
GAYVER
Цитата(v1vas @ Mar 24 2015, 22:32) *
Это не майнер, это очень специфичный брут-форс для очень экзотичной задачи)



это что же за брутфорс такой, для реализации которого понадобилось фигачить проект на fpga ))?
iosifk
Цитата(v1vas @ Mar 24 2015, 20:42) *
Давайте вдаваться в детали, чтобы все не выглядело так ужасно, как это понял iosifk =)

Есть вычислительный модуль, в нем достаточно легковесная математика. Он единоразово принимает 34 байта стартовых данных и далее на протяжении примерно 5 500 000 000 шагов (1 шаг - 1 такт) эти данные обрабатывает. При частоте 200МГц - это около 30 секунд. В процессе этих 30 секунд никакие данные модулю больше не нужны.

Причем, PlanAhead показывает, что критические пути - это линии соединения вычислительных модулей с центральным.


Вот , о чем я и написал... Плохой подход гонять параллельные шины и делать все "в лоб".

Сделайте так:
В центральный модуль добавье что-то вроде SPI, который будет передавать-принимать из вычислителей данные в последовательном коде. При 30 сек добавить еще несколько тактов на 34 бита - думаю что это проблемой не будет...
dvladim
Передача через входную шину идёт редко. Дёргайте data_flag не каждый такт, а раз в три такта плюс set_multicycle_path.
PS. Брутфорс экономичнее делать на более мелких ПЛИС как вот эти.
iosifk
Цитата(iosifk @ Apr 3 2015, 15:05) *
Вот , о чем я и написал... Плохой подход гонять параллельные шины и делать все "в лоб".

Сделайте так:
В центральный модуль добавье что-то вроде SPI, который будет передавать-принимать из вычислителей данные в последовательном коде. При 30 сек добавить еще несколько тактов на 34 бита - думаю что это проблемой не будет...


Я бы даже предложил не просто "вроде SPI", а что-то "вроде JTAG". Т.е. последовательную шину развести транзитом через все модули - это сильно экономит интерконнекты. И так же как в JTAG тем для кого информация не предназначена - режим Байпас - это только 1 триггер на приеме. А тому, кто должен получить данные - 34 бита. Про это подробнее - в моих статьях.

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.