Чи можуть швидші процесори / тактові годинники виконувати більше коду?


9

Я пишу програму для роботи на ATmega 328, який працює на 16 МГц (це Arduino Duemilanove, якщо ви їх знаєте, це чіп AVR).

У мене процес переривання працює кожні 100 мікросекунд. Я б сказав, неможливо, розробити, скільки «коду» ви можете виконати за один цикл 100 мікросекунд (я пишу в C, який, імовірно, перетворюється на збірку, потім у двійкове зображення?).

Також це залежатиме від складності коду (наприклад, один гігантський вкладиш може працювати повільніше, ніж кілька коротких рядків).

Чи правильно я розумію, що мій процесор з тактовою частотою або 16 МГц виконує 16 мільйонів циклів в секунду (це означає 16 циклів на мікросекунду 16 000 000/1000/1000); І тому, якщо я хочу зробити більше в своєму мікро мікросекундному циклі, придбання більш швидкої моделі, як версія 72 МГц, дасть мені 72 цикли на мікросекунду (72 000 000/1000/1000)?

В даний час він працює трохи повільно, тобто для його циклу потрібно трохи більше 100 мікросекунд (скільки часу точно занадто важко сказати, але він поступово відстає), і я хотів би зробити це ще трохи, це розумний підхід, який отримує швидший чіп чи я зійшов з розуму?


.... ATmega328 НЕ є чіпом ARM. Це AVR.
vicatcu

Ура, виправлено!
jwbensley

Відповіді:


9

Загалом, кількість інструкцій по збірці, які може виконати пристрій за секунду, буде залежати від набору інструкцій та кількості циклів, який повинен виконувати кожен тип інструкцій (CPI). Теоретично ви можете підрахувати свій код, переглянувши розібраний файл ASM та переглянувши функцію, яка вас хвилює, підрахувати всі різні типи інструкцій у ньому та переглянути підрахунок циклу з таблиці даних для вашого цільового процесора.

Проблема визначення ефективної кількості інструкцій в секунду загострюється у більш складних процесорах через те, що вони конвеєрні та мають кеші, а що ні. Це не стосується такого простого пристрою, як ATMega328, який є єдиною інструкцією польотного процесора.

Що стосується практичних питань, то для такого простого пристрою, як AVR, моя відповідь була б більш-менш "так". Подвоєння вашої тактової частоти має наполовину перевищувати час виконання будь-якої функції. Однак для AVR вони не працюватимуть швидше, ніж 20 МГц, тому ви могли лише розігнати свій Arduino ще на 4 МГц.

Ця порада не узагальнює процесор, який має більш досконалі функції. Подвоєння тактової швидкості на вашому процесорі Intel практично не вдвічі перевищує кількість вказівок, які він виконує за секунду (через неправильні прогнози гілок, пропуски кешу тощо).


Привіт, дякую за інформативну відповідь! Я бачив один із них ( coolcomponents.co.uk/catalog/product_info.php?products_id=808 ), ви сказали, що AVR не може працювати швидше 20 МГц, чому це так? Мікросхема на вищевказаній платі ( uk.farnell.com/stmicroelectronics/stm32f103rbt6/… ) є 72 МГц ARM, чи можу я очікувати від цього розумного підвищення продуктивності способом, про який я описав вище?
jwbensley

2
Подвоєння швидкості обробки може не збільшити пропускну здатність вашої інструкції, оскільки ви можете почати перевищувати швидкість, з якою можна отримати інструкції зі спалаху. З цього моменту ви починаєте натискати "Стани очікування спалаху", де процесор зупиняється, поки він чекає, коли інструкція надійде зі спалаху. Деякі мікроконтролери обходять це, дозволяючи виконувати код з ОЗУ, який набагато швидше, ніж FLASH.
Majenko

@Majenko: Смішно, ми обоє зробили один і той же момент.
Jason S

Буває ... твій кращий, ніж мій :)
Маєнко

1
Гаразд, я позначив відповідь Вікатку як "відповідь". Я вважаю, що це було найбільш підходящим щодо мого оригінального питання про швидкість, що стосується продуктивності, хоча всі відповіді чудові, і я справді переслідував відповіді всіх. Вони показали мені, що це більш широкий предмет, ніж я вперше зрозумів, і так, усі вони мене багато навчають і дають мені багато досліджень, тому дякую всім: D
jwbensley

8

Відповідь @ vicatcu досить вичерпна. Ще одне, що потрібно відзначити, - це те, що при доступі до вводу-виводу процесор може працювати в станах очікування (зупинені цикли процесора), включаючи пам'ять програми та даних.

Наприклад, ми використовуємо TI F28335 DSP; деякі області оперативної пам’яті є станом 0-очікування для пам'яті програми та даних, тому при виконанні коду в оперативній пам’яті він працює з 1 циклом за інструкцією (за винятком тих інструкцій, які займають більше 1 циклу). Коли ви виконуєте код з пам'яті FLASH (вбудований EEPROM, більш-менш), він не може працювати на повному 150 МГц і в кілька разів повільніше.


Що стосується високошвидкісного коду переривання, ви повинні вивчити ряд речей.

По-перше, ознайомтеся зі своїм компілятором. Якщо компілятор робить хорошу роботу, це не повинно бути набагато повільніше, ніж ручне складання для більшості речей. (де "що набагато повільніше": коефіцієнт 2 мій буде нормальним; коефіцієнт 10 буде неприйнятним) Вам потрібно навчитися (і коли) використовувати прапори оптимізації компілятора, і раз у раз ви повинні шукати на виході компілятора, щоб побачити, як це робиться.

Деякі інші речі, які можна зробити компілятором для прискорення коду:

  • використовувати вбудовані функції (не пам'ятаю, чи підтримує це C або це лише C ++ - ism), як для невеликих функцій, так і для функцій, які виконуються лише один чи два рази. Недоліком вбудованих функцій важко налагодити, особливо якщо включена оптимізація компілятора. Але вони заощаджують вам непотрібні послідовності виклику / повернення, особливо якщо абстракція "функції" призначена для концептуальної розробки, а не для реалізації коду.

  • Перегляньте посібник Вашого компілятора, щоб побачити, чи має він внутрішні функції - це вбудовані функції, вбудовані залежно від компілятора, які відображаються безпосередньо в інструкції зі збирання процесора; деякі процесори мають інструкції по збірці, які роблять корисні речі, такі як min / max / біт назад, і ви можете заощадити час.

  • Якщо ви робите числові обчислення, переконайтеся, що ви не викликаєте зайвих функцій математичної бібліотеки. У нас був один випадок, коли код був чимось на зразок y = (y+1) % 4лічильника, який мав період 4, очікуючи, що компілятор реалізує модуль 4 як біт-AND. Натомість вона називається математичною бібліотекою. Тож ми замінили y = (y+1) & 3робити те, що хотіли.

  • Ознайомтеся зі сторінкою хак-битів . Я гарантую, що ви будете користуватися принаймні одним із них часто.

Ви також повинні використовувати таймерські периферійні пристрої процесора для вимірювання часу виконання коду - у більшості з них є таймер / лічильник, який можна встановити для роботи на тактовій частоті процесора. Зробіть копію лічильника на початку та в кінці вашого критичного коду, і ви зможете побачити, як триває це. Якщо ви не можете цього зробити, іншою альтернативою є опустити вихідний штифт на початку коду і підняти його в кінці, і подивитися на цей вихід на осцилограмі, щоб вчасно виконати виконання. У кожному підході є компроміси: внутрішній таймер / лічильник є більш гнучким (ви можете витратити декілька речей), але складніше вивести інформацію, тоді як встановлення / очищення вихідного штифта відразу видно на області застосування, і ви можете фіксувати статистику, але важко відрізнити кілька подій.

Нарешті, є дуже важливий навик, який має досвід - як загальний, так і конкретні комбінації процесор / компілятор: знати, коли і коли не оптимізувати . Взагалі відповідь не оптимізувати. Цитата Дональда Кнута часто публікується на StackOverflow (зазвичай це лише остання частина):

Слід забути про невелику ефективність, скажімо, про 97% часу: передчасна оптимізація - корінь усього зла

Але ви потрапили в ситуацію, коли ви знаєте, що вам потрібно зробити якусь оптимізацію, тож саме час кусати кулю і оптимізувати (або отримати швидший процесор, або те й інше). Ви НЕ писати всю ISR в зборі. Це майже гарантована катастрофа - якщо ви це зробите, протягом місяців або навіть тижнів ви забудете частину того, що ви зробили і чому, і код, ймовірно, буде дуже крихким і важко змінити. Однак, ймовірно, є частини вашого коду, які є хорошими кандидатами на збірку.

Ознаки того, що частини вашого коду добре підходять для кодування збірки:

  • функції, які добре містять чітко визначені невеликі процедури, навряд чи зміниться
  • функції, які можуть використовувати конкретні інструкції по збірці (min / max / shift shift / тощо)
  • функції, які дзвонять багато разів (отримує вам множник: якщо ви зберігаєте 0,5usec на кожному дзвінку, і він викликається 10 разів, це заощаджує вам 5 Usec, що важливо у вашому випадку)

Дізнайтеся про функції вашого компілятора, що викликає конвенції (наприклад, де він розміщує аргументи в регістри та які регістри зберігає / відновлює), щоб ви могли писати підпрограми складання на C-дзвінки.

У моєму теперішньому проекті у нас є досить велика база коду з критичним кодом, який повинен працювати в 10 кГц переривання (100usec - звук знайомий?), І не так багато функцій, які записані в зборі. Це такі речі, як обчислення CRC, черги програмного забезпечення, компенсація посилення / компенсації ADC.

Удачі!


хороша порада щодо методів вимірювання часу емпіричного виконання
vicatcu

Ще одна чудова відповідь на моє запитання, дуже дякую Джейсону S за цей дивовижний шматок знань! Дві речі, очевидні після прочитання цього; По-перше, я можу підвищити переривання від кожні 100uS до 500uS, щоб дати коду більше часу на виконання, я розумію, що зараз це не дуже корисно для мене, коли я так швидко. По-друге, я вважаю, що мій код може бути занадто неефективним, якщо триваліший час переривання і кращий код, все може бути добре. Stackoverflow - це краще місце для розміщення коду, тому я опублікую його там і покладу на нього посилання, якщо хтось захоче подивитися і дати будь-які рекомендації, будь ласка, виконайте: D
jwbensley

5

Ще одне, що слід зазначити - напевно, ви можете виконати деякі оптимізації, щоб зробити ваш код більш ефективним.

Наприклад - у мене є рутина, яка запускається всередині таймера переривання. Програма повинна завершитися протягом 52 мкЗ, і вона повинна переробляти велику кількість пам'яті, виконуючи це.

Мені вдалося значно збільшити швидкість, заблокувавши головну змінну лічильника в регістрі (на моєму компіляторі µC & - для вашого)

register unsigned int pointer asm("W9");

Я не знаю формату для вашого компілятора - RTFM, але ви можете щось зробити, щоб зробити вашу рутину швидшою, не потребуючи переходу на збірку.

Сказавши це, ви, ймовірно, можете зробити набагато кращу роботу з оптимізації вашого розпорядку, ніж компілятор, тому перехід на збірку цілком може принести вам значне збільшення швидкості.


lol я "одночасно" прокоментував мою власну відповідь про налаштування асемблера та розподіл регістра :)
vicatcu

Якщо на 16 МГц процесор займає 100us - це, очевидно, досить величезно, тому це багато коду для оптимізації. Я чув, що компілятори сьогодні виробляють приблизно в 1,1 рази більше коду, ніж оптимізована вручну збірка. Зовсім не варто цього величезного розпорядку. Можливо, для гоління на 20% знижки на 6-ти
рядкову

1
Не обов’язково ... Це може бути всього 5 рядків коду в циклі. І справа не в розмірі коду, а в ефективності коду . Можливо, ви зможете записати код інакше, змусивши його працювати швидше. Я знаю, що я робив, що я робив. Наприклад, жертвуючи розміром для швидкості. Запустивши один і той же код 10 разів послідовно, ви заощадите час наявності коду для виконання циклу - та пов'язаних змінних лічильників. Так, код у 10 разів довший, але він працює швидше.
Majenko

Привіт Маєнко, я не знаю складання, але я думав про те, щоб навчитися цьому, і думав, що Arduino буде менш складним, ніж мій настільний комп'ютер, тому це міг би бути гарним часом для навчання, тим більше, що я хочу знати докладніше про те, що відбувається і нижчий рівень. Як говорили інші, я б не переписав всю річ лише з певних частин. Я розумію, що я можу занести ASM і вийти з нього в межах C, це правильно, чи так можна досягти цієї суміші C і ASM? Я опублікую на stackoverflow для специфіки, відразу після загальної ідеї.
jwbensley

@javano: Так. Ви можете запускати та виходити з ASM в межах C. Багато вбудованих систем було написано так - у суміші C і збірки - головним чином тому, що в примітивних компіляторах C, доступних у час. Однак сучасні компілятори C, такі як gcc (який є компілятором, який використовує Arduino), зараз обробляють більшість, а в багатьох випадках і всі речі, для яких потрібна мова складання.
davidcary
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.