더 빠른 프로세서 / 클럭이 더 많은 코드를 실행할 수 있습니까?


9

나는 16Mhz에서 실행되는 ATmega 328에서 실행되는 프로그램을 작성하고 있습니다 (아두 이노 Duemilanove는 알고 있다면 AVR 칩입니다).

100 마이크로 초마다 실행되는 인터럽트 프로세스가 있습니다. 100 마이크로 초의 한 루프에서 얼마나 많은 "코드"를 실행할 수 있는지는 불가능합니다 (아마도 어셈블리로 변환 된 다음 이진 이미지로 변환되는 C로 작성하고 있습니까?).

또한 이것은 코드의 복잡성에 달려 있습니다 (예를 들어 거대한 하나의 라이너는 여러 개의 짧은 라인보다 느리게 실행될 수 있습니다).

클럭 속도 또는 16Mhz의 프로세서가 초당 1600 만 사이클 (마이크로 초당 16 사이클 16,000,000 / 1,000 / 1,000을 수행함)을 수행한다는 점을 이해하고 있습니까? 따라서 100 마이크로 초 루프에서 더 많은 것을 원한다면 72Mhz 버전과 같은 더 빠른 모델을 구입하면 마이크로 초 당 72 사이클 (72,000,000 / 1,000 / 1,000)입니까?

현재 그것은 너무 느리게 실행됩니다. 즉, 루프를 수행하는 데 100 마이크로 초보다 조금 오래 걸립니다 (얼마나 오래 말하기는 어렵지만 점차적으로 뒤떨어집니다) 그리고 조금 더하고 싶습니다. 이것은 더 빠른 칩을 얻는 건전한 접근법입니까?


.... ATmega328은 ARM 칩이 아닙니다. AVR입니다.
vicatcu

답변:


9

일반적으로 장치가 초당 실행할 수있는 어셈블리 명령어 수는 명령어 믹스각 명령어 유형 (CPI)이 실행하는 데 걸리는주기 수 에 따라 다릅니다 . 이론적으로 디스 어셈블 된 asm 파일을보고 관심있는 기능을보고, 코드의 모든 다른 유형의 명령을 세고, 대상 프로세서의 데이터 시트에서주기 수를 찾아서 코드를 계산할 수 있습니다.

결정의 문제 효과적인 초당 지침의 수는이 파이프 라인과하고있는 캐시를 어떤되지 않는다는 사실에 의해 더 복잡한 프로세서에 악화된다. 이것은 비행 프로세서에서 단일 명령 인 ATMega328과 같은 간단한 장치의 경우에는 해당되지 않습니다.

실질적인 문제와 관련하여 AVR과 같은 간단한 장치의 경우 제 대답은 "예"입니다. 클럭 속도를 두 배로 늘리면 지정된 기능의 실행 시간이 절반으로 줄어 듭니다. 그러나 AVR의 경우 20MHz보다 빠르게 실행되지 않으므로 다른 4MHz만큼 Arduino를 "오버 클로킹"할 수 있습니다.

이 조언은 고급 기능을 가진 프로세서를 일반화 하지는 않습니다 . 인텔 프로세서의 클럭 속도를 두 배로 늘리면 실제로 분기 오판, 캐시 누락 등으로 인해 초당 실행되는 명령 수가 두 배가되지는 않습니다.


유익한 답변 감사합니다. 나는 이것들 중 하나를 보았습니다 ( coolcomponents.co.uk/catalog/product_info.php?products_id=808 ), 당신은 AVR이 20Mhz보다 더 빠를 수 없다고 말했습니다. 왜 그런가요 ? 위 보드의 칩 ( uk.farnell.com/stmicroelectronics/stm32f103rbt6/… )은 72Mhz ARM인데, 위에서 설명한 방식으로 이로부터 합리적인 성능 향상을 기대할 수 있습니까?
jwbensley 2016 년

2
처리 속도를 두 배로 늘리면 명령을 플래시에서 가져올 수있는 속도를 초과 할 수 있으므로 명령 처리량을 늘리지 못할 수 있습니다. 이 시점에서 명령이 플래시에서 도착할 때까지 CPU가 일시 중지되는 "플래시 대기 상태"에 도달하기 시작합니다. 일부 마이크로 컨트롤러는 FLASH보다 훨씬 빠른 RAM에서 코드를 실행할 수 있도록하여이 문제를 해결합니다.
Majenko

@Majenko : 우스운, 우리 둘 다 동시에 같은 지점을 만들었습니다.
Jason S

그것은 일어난다 ... 당신은 내 것보다 낫다 :)
Majenko

1
저는 Vicatcu의 답변을 "답변"으로 표시했습니다. 모든 답변이 훌륭하고 모든 사람의 답변으로 가득 차 있지만 성능과 관련된 속도에 대한 원래의 질문과 관련하여 가장 적절하다고 생각합니다. 그들은 그것이 내가 처음 깨달은 것보다 더 넓은 주제라는 것을 보여 주었고, 그래서 그들은 모두 나에게 많은 것을 가르치고 나에게 많은 연구를 해주므로 모두에게 감사합니다. D
jwbensley

8

@vicatcu의 답변은 매우 포괄적입니다. 주목해야 할 또 다른 사항은 프로그램 및 데이터 메모리를 포함하여 I / O에 액세스 할 때 CPU가 대기 상태 (스톨 된 CPU주기)로 실행될 수 있다는 것 입니다.

예를 들어 TI F28335 DSP를 사용하고 있습니다. RAM의 일부 영역은 프로그램 및 데이터 메모리에 대해 0- 대기 상태이므로 RAM에서 코드를 실행할 때 명령 당 1 사이클로 실행됩니다 (1 사이클을 초과하는 명령은 제외). 그러나 FLASH 메모리 (내장 EEPROM 등)에서 코드를 실행할 때는 최대 150MHz에서 실행할 수 없으며 몇 배 느립니다.


고속 인터럽트 코드와 관련하여 많은 것을 배워야합니다.

먼저 컴파일러에 익숙해 지십시오. 컴파일러가 제대로 작동한다면 대부분의 경우 수작업으로 코딩 된 어셈블리보다 훨씬 느리지 않아야합니다. (여기서 "너무 느리게": 2의 인자는 괜찮을 것입니다; 10의 인자는 용납 할 수 없습니다) 컴파일러 최적화 플래그를 사용하는 방법과시기를 배우고 가끔씩 살펴 봐야합니다. 컴파일러 출력에서 ​​어떻게 작동하는지 확인하십시오.

컴파일러가 코드 속도를 높이기 위해 할 수있는 몇 가지 사항 :

  • 작은 함수와 한두 번만 실행될 함수에 대해 인라인 함수를 사용하십시오 (C가이를 지원하는지 또는 C ++-ism 인 경우는 기억 나지 않습니다). 단점은 특히 컴파일러 최적화가 설정된 경우 인라인 함수를 디버깅하기 어렵다는 것입니다. 그러나 특히 "함수"추상화가 코드 구현이 아닌 개념적 설계 목적인 경우 불필요한 호출 / 반환 시퀀스를 절약 할 수 있습니다.

  • 컴파일러 설명서를 참조하여 내장 함수가 있는지 확인하십시오. 이러한 함수는 프로세서의 어셈블리 명령어에 직접 매핑되는 컴파일러 종속 내장 함수입니다. 일부 프로세서에는 min / max / bit reverse와 같은 유용한 작업을 수행하는 어셈블리 명령어가 있으므로 시간을 절약 할 수 있습니다.

  • 숫자 계산을 수행하는 경우 수학 라이브러리 함수를 불필요하게 호출하지 않아야합니다. y = (y+1) % 4컴파일러가 모듈로 4를 비트 단위 AND로 구현할 것으로 기대하는 기간이 4 인 카운터 와 같은 코드 인 경우 가있었습니다. 대신 수학 라이브러리라고 불렀습니다. 그래서 우리 y = (y+1) & 3는 원하는 것을 대신 했습니다.

  • 비트 트위들 링 해킹 페이지에 익숙해 지십시오 . 나는 당신이 이것들 중 하나 이상을 자주 사용할 것을 보장합니다.

또한 코드 실행 시간을 측정하기 위해 CPU의 타이머 주변 장치를 사용해야합니다. 대부분 CPU 타이머 주파수에서 실행되도록 설정할 수있는 타이머 / 카운터가 있습니다. 중요 코드의 시작과 끝에서 카운터 사본을 캡처하면 시간이 얼마나 걸리는지 확인할 수 있습니다. 그렇게 할 수 없다면 코드의 시작 부분에서 출력 핀을 내리고 끝에서 올린 다음 오실로스코프에서이 출력을보고 실행 시간을 정하는 것입니다. 각 접근 방식에는 장단점이 있습니다. 내부 타이머 / 카운터는 더 유연하지만 (몇 가지 시간을 정할 수는 있지만) 정보를 얻기가 더 어렵지만 출력 핀 설정 / 삭제는 스코프에서 즉시 볼 수 있으며 통계를 캡처 할 수는 있지만 여러 이벤트를 구별하기가 어렵습니다.

마지막으로, 일반 및 특정 프로세서 / 컴파일러 조합과 함께 경험과 함께 제공되는 매우 중요한 기술이 있습니다. 최적화시기와시기를 아는 것 입니다. 일반적으로 대답은 최적화되지 않습니다. Donald Knuth 견적은 StackOverflow에 자주 게시됩니다 (보통 마지막 부분).

우리는 작은 효율성에 대해 잊어야합니다.

그러나 어떤 종류의 최적화를 수행해야하는 상황에 처해 있으므로 총알을 깨물고 최적화 (또는 더 빠른 프로세서 또는 둘 다)해야합니다. 전체 ISR을 조립품으로 쓰지 마십시오 . 이는 거의 보장 된 재난입니다. 재난이 발생하면 몇 개월 또는 몇 주 내에 수행 한 작업의 일부와 이유를 잊어 버릴 수 있으며 코드가 매우 취약하여 변경하기가 어렵습니다. 그, 그러나, 코드의 일부가 될 가능성이있다 있는 어셈블리에 대한 좋은 후보.

코드의 일부가 어셈블리 코딩에 적합하다는 표시 :

  • 잘 포함되고 잘 정의 된 작은 루틴이 변경되지 않는 함수
  • 특정 조립 지침을 활용할 수있는 기능 (최소 / 최대 / 오른쪽 시프트 등)
  • 여러 번 호출되는 함수 (승수를 얻습니다 : 각 호출마다 0.5usec를 저장하고 10 번 호출하면 5 usec가 절약됩니다)

C 호출 가능 어셈블리 루틴을 작성할 수 있도록 컴파일러의 함수 호출 규칙 (예 : 인수를 레지스터에 넣는 위치 및 저장 / 복원하는 레지스터)을 익히십시오.

현재 프로젝트에는 10kHz 인터럽트 (100usec-익숙한 소리)에서 실행 해야하는 중요한 코드가있는 매우 큰 코드베이스가 있으며 어셈블리에 작성된 많은 함수는 없습니다. CRC 계산, 소프트웨어 대기열, ADC 게인 / 오프셋 보상 등이 있습니다.

행운을 빕니다!


경험적 실행 시간 측정 기술에 대한 좋은 조언
vicatcu

내 질문에 대한 또 다른 좋은 대답입니다.이 놀라운 지식에 대해 Jason S에게 감사드립니다! 이것을 읽은 후 명백한 두 가지; 첫째, 코드를 실행할 시간을 더주기 위해 모든 100uS에서 500uS로 인터럽트를 올릴 수 있습니다. 둘째, 내 코드가 너무 비효율적이라고 생각합니다. 인터럽트 시간이 길고 코드가 좋을수록 좋습니다. Stackoverflow는 코드를 게시하기에 더 좋은 곳입니다. 따라서 누군가
가보고

5

주의해야 할 또 다른 사항-코드를보다 효율적으로 만들기 위해 수행 할 수있는 최적화가있을 수 있습니다.

예를 들어-타이머 인터럽트 내에서 실행되는 루틴이 있습니다. 이 루틴은 52µS 이내에 완료되어야하며, 수행하는 동안 많은 양의 메모리를 거쳐야합니다.

나는 메인 카운터 변수를 레지스터에 고정시켜 큰 속도 증가를 관리했다.

register unsigned int pointer asm("W9");

컴파일러의 형식 인 RTFM을 모르지만 어셈블리로 전환하지 않고도 루틴을 더 빠르게 만들 수있는 방법이 있습니다.

그러나 컴파일러보다 루틴을 최적화하는 데 훨씬 나은 작업을 수행 할 수 있으므로 어셈블리로 전환하면 속도가 크게 향상 될 수 있습니다.


LOL 나는 "동시에"어셈블러 조정에 대한 내 자신의 대답에 댓글 및 할당 : 등록
vicatcu

16MHz 프로세서에서 100us를 사용하는 경우 분명히 엄청 나기 때문에 최적화 할 코드가 많이 있습니다. 오늘날 컴파일러는 수동 최적화 어셈블리보다 약 1.1 배의 코드를 생성한다고 들었습니다. 그런 거대한 루틴에 대해서는 그만한 가치가 없습니다. 아마도 6 라인 기능에서 20 % 할인, 아마도 ...
DefenestrationDay

1
반드시 그런 것은 아닙니다 ... 루프에서 5 줄의 코드 일 수 있습니다. 그리고 코드 크기가 아니라 코드 효율성 에 관한 입니다. 코드를 다르게 작성하여 코드를 더 빠르게 실행할 수 있습니다. 나는 내가 저지른 인터럽트 루틴을 알고있다. 예를 들어, 속도를 위해 크기를 희생합니다. 동일한 코드를 순서대로 10 번 실행하면 루프 및 관련 카운터 변수를 수행하는 코드 시간을 절약 할 수 있습니다. 예, 코드는 10 배 길지만 더 빠르게 실행됩니다.
Majenko

안녕하세요 Majenko, 나는 어셈블리를 모르지만 그것을 배우는 것에 대해 생각하고 있었고, Arduino가 내 데스크탑 컴퓨터보다 덜 복잡 할 것이라고 생각하고 있었기 때문에 특히 배우고 싶은 좋은 시간이 될 수 있습니다. 무슨 일이 일어나고 있는지, 더 낮은 수준에 대해 다른 사람들이 말했듯이, 나는 모든 것을 특정 부분 만 다시 쓰지 않을 것입니다. 내 이해는 C 내에서 ASM을 탈퇴 할 수 있다는 것입니다.이 맞습니까?이 C와 ASM의 혼합을 달성하는 방법입니까? 나는 일반적인 아이디어 직후에 세부 사항에 대한 stackoverflow에 게시 할 것입니다.
jwbensley 2016 년

@javano : 그렇습니다. C 내에서 ASM을 넣거나 꺼낼 수 있습니다. 대부분의 임베디드 시스템은 C와 어셈블리를 혼합하여 작성했습니다 . 주로 C에서 사용할 수없는 기본 C 컴파일러로는 수행 할 수 없었던 몇 가지 사항이 있었기 때문입니다. 시각. 그러나 gcc (Arduino에서 사용하는 컴파일러)와 같은 최신 C 컴파일러는 이제 어셈블리 언어를 요구하는 데 사용되는 모든 것을 처리합니다.
davidcary
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.