Bộ xử lý / đồng hồ nhanh hơn có thể thực thi nhiều mã hơn không?


9

Tôi đang viết một chương trình để chạy trên ATmega 328 chạy ở tốc độ 16Mhz (đó là Arduino Duemilanove nếu bạn biết chúng, đó là chip AVR).

Tôi có một quá trình gián đoạn chạy cứ sau 100 micro giây. Tôi không thể nói rằng, để tìm ra bao nhiêu "mã" bạn có thể thực thi trong một vòng 100 micro giây (Tôi đang viết bằng C có lẽ được chuyển đổi thành lắp ráp thành hình ảnh nhị phân?).

Ngoài ra, điều này sẽ phụ thuộc vào độ phức tạp của mã (một lớp lót khổng lồ có thể chạy chậm hơn một vài dòng ngắn chẳng hạn).

Sự hiểu biết của tôi có đúng không, trong đó bộ xử lý của tôi có tốc độ xung nhịp hoặc 16Mhz thực hiện 16 triệu chu kỳ mỗi giây (điều này có nghĩa là 16 chu kỳ mỗi micro giây 16.000.000 / 1.000 / 1.000); Và vì vậy, nếu tôi muốn làm nhiều hơn trong vòng lặp 100 micro giây của mình, việc mua một mô hình nhanh hơn như phiên bản 72Mhz sẽ cho tôi 72 chu kỳ mỗi micro giây (72.000.000 / 1.000 / 1.000)?

Hiện tại nó chỉ chạy hơi chậm, tức là mất hơn 100 micro giây để thực hiện vòng lặp (chính xác là quá khó để nói, nhưng nó dần tụt lại phía sau) và tôi muốn nó làm nhiều hơn một chút, là Đây là một cách tiếp cận lành mạnh để có được một con chip nhanh hơn hoặc tôi đã phát điên?


.... Một ATmega328 KHÔNG phải là chip ARM. Đó là một AVR.
Abbeyatcu

Chúc mừng, đã sửa!
jwbensley

Câu trả lời:


9

Nói chung, số lượng lệnh lắp ráp mà thiết bị có thể thực hiện mỗi giây sẽ phụ thuộc vào hỗn hợp lệnhsố lượng mỗi loại lệnh được thực hiện (CPI) để thực hiện. Trong chu trình lý thuyết, bạn có thể đếm mã của mình bằng cách xem tệp asm đã tháo rời và xem hàm bạn quan tâm, đếm tất cả các loại hướng dẫn khác nhau trong đó và tìm kiếm số đếm chu kỳ từ bảng dữ liệu cho bộ xử lý đích của bạn.

Vấn đề xác định số lượng hướng dẫn hiệu quả mỗi giây trở nên trầm trọng hơn trong các bộ xử lý phức tạp hơn bởi thực tế là chúng được đặt trong đường ống và có bộ đệm và những gì không. Đây không phải là trường hợp của một thiết bị đơn giản như ATMega328 mà là một hướng dẫn duy nhất trong bộ xử lý chuyến bay.

Đối với các vấn đề thực tế, đối với một thiết bị đơn giản như AVR, câu trả lời của tôi sẽ ít nhiều là "có". Nhân đôi tốc độ đồng hồ của bạn sẽ bằng một nửa thời gian thực hiện của bất kỳ chức năng nào. Tuy nhiên, đối với một AVR, chúng sẽ không chạy nhanh hơn 20 MHz, do đó bạn chỉ có thể "ép xung" Arduino của mình thêm 4 MHz.

Lời khuyên này không khái quát cho bộ xử lý có các tính năng nâng cao hơn. Nhân đôi tốc độ xung nhịp trên bộ xử lý Intel của bạn trong thực tế sẽ không tăng gấp đôi số lượng lệnh mà nó thực thi mỗi giây (vì dự đoán sai nhánh, lỗi bộ nhớ cache, v.v.).


Xin chào, cảm ơn câu trả lời đầy thông tin của bạn! Tôi đã thấy một trong số này ( coolcomponents.co.uk/catalog/product_info.php?products_id=808 ), bạn nói rằng một AVR không thể đi nhanh hơn 20Mhz, tại sao vậy? Con chip trên bảng trên ( uk.farnell.com/stmicroelectronics/stm32f103rbt6/ mẹo) là một ARM 72Mhz, tôi có thể mong đợi sự gia tăng hiệu suất hợp lý từ cách này như tôi đã mô tả ở trên không?
jwbensley

2
Nhân đôi tốc độ xử lý có thể không làm tăng thông lượng chỉ dẫn của bạn vì bạn có thể bắt đầu vượt quá tốc độ mà các hướng dẫn có thể được tìm nạp từ đèn flash. Tại thời điểm này, bạn bắt đầu nhấn "Trạng thái chờ flash" trong đó CPU tạm dừng trong khi nó chờ lệnh đến từ đèn flash. Một số bộ vi điều khiển làm tròn điều này bằng cách cho phép bạn thực thi mã từ RAM nhanh hơn nhiều so với FLASH.
Majenko

@Majenko: buồn cười, cả hai chúng tôi đều có cùng quan điểm cùng một lúc.
Jason S

Nó xảy ra ... của bạn tốt hơn của tôi :)
Majenko

1
OK, tôi đã đánh dấu câu trả lời của Vicatcu là "câu trả lời". Tôi cảm thấy nó phù hợp nhất với câu hỏi ban đầu của tôi về tốc độ liên quan đến hiệu suất mặc dù tất cả các câu trả lời đều rất hay và tôi thực sự cảm thấy khó chịu với câu trả lời của mọi người. Họ đã cho tôi thấy rằng đó là một chủ đề rộng hơn tôi nhận ra lần đầu tiên, và vì vậy, tất cả họ đều dạy tôi rất nhiều và cho tôi rất nhiều nghiên cứu, vì vậy xin cảm ơn tất cả mọi người: D
jwbensley

8

Câu trả lời của @ Abbeyatcu là khá toàn diện. Một điều nữa cần lưu ý là CPU có thể chạy trong trạng thái chờ (chu kỳ CPU bị đình trệ) khi truy cập I / O, bao gồm bộ nhớ chương trình và dữ liệu.

Ví dụ: chúng tôi đang sử dụng TI F28335 DSP; Một số vùng của RAM là trạng thái chờ 0 cho bộ nhớ chương trình và dữ liệu, vì vậy khi bạn thực thi mã trong RAM, nó sẽ chạy ở 1 chu kỳ trên mỗi lệnh (ngoại trừ các hướng dẫn mất hơn 1 chu kỳ). Tuy nhiên, khi bạn thực thi mã từ bộ nhớ FLASH (EEPROM tích hợp, nhiều hay ít), nó không thể chạy ở mức đầy đủ 150 MHz và chậm hơn nhiều lần.


Đối với mã ngắt tốc độ cao, bạn phải tìm hiểu một số điều.

Đầu tiên, trở nên rất quen thuộc với trình biên dịch của bạn. Nếu trình biên dịch thực hiện công việc tốt, thì nó không nên chậm hơn nhiều so với lắp ráp bằng tay cho hầu hết mọi thứ. (trong đó "chậm hơn nhiều": hệ số 2 sẽ ổn với tôi; hệ số 10 sẽ không được chấp nhận) Bạn cần tìm hiểu cách (và khi nào) sử dụng cờ tối ưu hóa trình biên dịch, và thỉnh thoảng bạn nên xem tại đầu ra của trình biên dịch để xem nó hoạt động như thế nào.

Một số điều khác mà bạn có thể có trình biên dịch làm để tăng tốc mã:

  • sử dụng các hàm nội tuyến (không thể nhớ nếu C hỗ trợ điều này hoặc nếu đó chỉ là C ++ - ism), cho cả các chức năng nhỏ và cho các chức năng sẽ chỉ được thực hiện một hoặc hai lần. Nhược điểm là các hàm nội tuyến khó gỡ lỗi, đặc biệt là nếu tối ưu hóa trình biên dịch được bật. Nhưng chúng giúp bạn tiết kiệm các chuỗi cuộc gọi / trả lại không cần thiết, đặc biệt nếu sự trừu tượng hóa "chức năng" là dành cho mục đích thiết kế khái niệm hơn là thực thi mã.

  • Xem hướng dẫn sử dụng của trình biên dịch của bạn để xem nó có các hàm nội tại hay không - đây là các hàm dựng sẵn phụ thuộc vào trình biên dịch ánh xạ trực tiếp đến các hướng dẫn lắp ráp của bộ xử lý; một số bộ xử lý có hướng dẫn lắp ráp thực hiện những việc hữu ích như đảo ngược min / max / bit và bạn có thể tiết kiệm thời gian thực hiện.

  • Nếu bạn đang thực hiện tính toán số, hãy đảm bảo rằng bạn không gọi các hàm thư viện toán học một cách không cần thiết. Chúng tôi đã có một trường hợp mã giống như y = (y+1) % 4một bộ đếm có chu kỳ 4, hy vọng trình biên dịch sẽ thực hiện modulo 4 dưới dạng bit-AND. Thay vào đó, nó được gọi là thư viện toán học. Vì vậy, chúng tôi thay thế y = (y+1) & 3để làm những gì chúng tôi muốn.

  • Làm quen với trang hack bit-twiddling . Tôi đảm bảo bạn sẽ sử dụng ít nhất một trong số này thường xuyên.

Bạn cũng nên sử dụng (các) thiết bị ngoại vi hẹn giờ của CPU để đo thời gian thực thi mã - hầu hết chúng đều có bộ hẹn giờ / bộ đếm có thể được đặt để chạy ở tần số xung nhịp CPU. Chụp một bản sao của bộ đếm ở đầu và cuối mã quan trọng của bạn và bạn có thể thấy nó mất bao lâu. Nếu bạn không thể làm điều đó, một cách khác là hạ thấp chân đầu ra ở đầu mã của bạn và nâng nó ở cuối và xem đầu ra này trên máy hiện sóng để xác định thời gian thực hiện. Có sự đánh đổi cho từng cách tiếp cận: bộ đếm thời gian / bộ đếm bên trong linh hoạt hơn (bạn có thể mất nhiều thời gian) nhưng khó lấy thông tin hơn, trong khi cài đặt / xóa mã pin đầu ra có thể nhìn thấy ngay lập tức trên một phạm vi và bạn có thể thu thập số liệu thống kê, nhưng thật khó để phân biệt nhiều sự kiện.

Cuối cùng, có một kỹ năng rất quan trọng đi kèm với kinh nghiệm - cả chung và với các kết hợp bộ xử lý / trình biên dịch cụ thể: biết khi nào và khi nào không tối ưu hóa . Nói chung, câu trả lời là không tối ưu hóa. Trích dẫn Donald Knuth được đăng thường xuyên trên StackOverflow (thường chỉ là phần cuối cùng):

Chúng ta nên quên đi những hiệu quả nhỏ, nói về 97% thời gian: tối ưu hóa sớm là gốc rễ của mọi tội lỗi

Nhưng bạn đang ở trong một tình huống mà bạn biết rằng bạn phải thực hiện một số loại tối ưu hóa, vì vậy đã đến lúc cắn viên đạn và tối ưu hóa (hoặc có bộ xử lý nhanh hơn hoặc cả hai). Đừng KHÔNG viết toàn bộ ISR của bạn trong lắp ráp. Đó gần như là một thảm họa được bảo đảm - nếu bạn làm điều đó, trong vòng vài tháng hoặc thậm chí vài tuần bạn sẽ quên đi những phần bạn đã làm và tại sao, và mã có thể rất dễ vỡ và khó thay đổi. Có khả năng là một phần mã của bạn, tuy nhiên, đó những ứng cử viên tốt để lắp ráp.

Dấu hiệu cho thấy các phần của mã của bạn rất phù hợp để mã hóa lắp ráp:

  • các chức năng có chứa thường xuyên, được xác định rõ các thói quen nhỏ không có khả năng thay đổi
  • các chức năng có thể sử dụng các hướng dẫn lắp ráp cụ thể (min / max / right shift / etc)
  • các hàm được gọi nhiều lần (giúp bạn nhân số nhân: nếu bạn tiết kiệm 0,5usec cho mỗi cuộc gọi và được gọi 10 lần, điều đó giúp bạn tiết kiệm 5 usec, điều này rất có ý nghĩa trong trường hợp của bạn)

Tìm hiểu các quy ước gọi hàm của trình biên dịch của bạn (ví dụ: nơi nó đặt các đối số trong các thanh ghi và đăng ký nào nó lưu / khôi phục) để bạn có thể viết các thói quen lắp ráp có thể gọi được C.

Trong dự án hiện tại của tôi, chúng tôi có một cơ sở mã khá lớn với mã quan trọng phải chạy trong ngắt 10kHz (100usec - nghe có quen không?) Và không có nhiều chức năng được viết trong cụm. Những thứ đó là, những thứ như tính toán CRC, hàng đợi phần mềm, bù / tăng bù ADC.

Chúc may mắn!


lời khuyên tốt về các kỹ thuật đo thời gian thực hiện theo kinh nghiệm
Abbeyatcu

Một câu trả lời tuyệt vời khác cho câu hỏi của tôi, cảm ơn Jason S rất nhiều vì khối kiến ​​thức tuyệt vời này! Hai điều rõ ràng sau khi đọc điều này; Đầu tiên, tôi có thể tăng ngắt từ mỗi 100uS lên 500uS để cung cấp mã nhiều thời gian hơn để thực thi, tôi nhận ra rằng điều này không thực sự mang lại lợi ích cho tôi nhanh như vậy. Thứ hai, tôi nghĩ rằng mã của tôi có thể quá kém hiệu quả, với thời gian gián đoạn dài hơn và mã tốt hơn tất cả có thể ổn. Stackoverflow là một nơi tốt hơn để đăng mã, vì vậy tôi sẽ đăng nó ở đó và đặt một liên kết đến đây, nếu có ai muốn xem và đưa ra bất kỳ đề xuất nào, vui lòng làm: D
jwbensley

5

Một điều cần lưu ý - có thể có một số tối ưu hóa bạn có thể thực hiện để làm cho mã của bạn hiệu quả hơn.

Ví dụ - Tôi có một thói quen chạy từ trong một bộ đếm thời gian. Thói quen phải hoàn thành trong vòng 52 giờ, và phải thực hiện một lượng lớn bộ nhớ trong khi thực hiện.

Tôi đã quản lý một sự gia tăng tốc độ lớn bằng cách khóa biến bộ đếm chính vào một thanh ghi với (trên trình biên dịch & trình biên dịch của tôi - khác với bạn):

register unsigned int pointer asm("W9");

Tôi không biết định dạng cho trình biên dịch của bạn - RTFM, nhưng sẽ có một số thứ bạn có thể làm để làm cho thói quen của mình nhanh hơn mà không phải chuyển sang lắp ráp.

Phải nói rằng, có lẽ bạn có thể thực hiện công việc tốt hơn nhiều trong việc tối ưu hóa thói quen của mình so với trình biên dịch, vì vậy việc chuyển sang lắp ráp cũng có thể giúp bạn tăng tốc độ rất lớn.


lol Tôi "đồng thời" nhận xét về câu trả lời của riêng tôi về điều chỉnh trình biên dịch và phân bổ đăng ký :)
Abbeyatcu

Nếu nó chiếm 100us trên bộ xử lý 16 MHz - thì rõ ràng nó khá lớn, vì vậy đó là rất nhiều mã để tối ưu hóa. Tôi đã nghe nói rằng trình biên dịch ngày nay tạo ra khoảng 1,1 lần mã so với lắp ráp bằng tay. Hoàn toàn không xứng đáng với một thói quen lớn như vậy. Để cạo 20% cho chức năng 6 dòng, có lẽ ...
DefenestrationDay

1
Không nhất thiết ... Nó có thể chỉ là 5 dòng mã trong một vòng lặp. Và đó không phải là về kích thước mã mà là về hiệu quả mã . Bạn có thể viết mã khác nhau để làm cho nó chạy nhanh hơn. Tôi biết cho thói quen gián đoạn của tôi, tôi đã làm. Ví dụ, hy sinh kích thước cho tốc độ. Bằng cách chạy cùng một mã 10 lần theo trình tự, bạn tiết kiệm thời gian có mã để thực hiện vòng lặp - và các biến đếm liên quan. Có, mã dài hơn 10 lần, nhưng nó chạy nhanh hơn.
Majenko

Xin chào Majenko, tôi không biết lắp ráp nhưng tôi đã suy nghĩ về việc học nó và đã nghĩ rằng Arduino sẽ ít phức tạp hơn máy tính để bàn của tôi vì vậy đây có thể là thời điểm tốt để tìm hiểu, đặc biệt là tôi muốn biết thêm về những gì đang xảy ra và một mức độ thấp hơn. Như những người khác đã nói, tôi sẽ không viết lại toàn bộ chỉ một số phần nhất định. Sự hiểu biết của tôi là tôi có thể vào và ra khỏi ASM trong C, điều này có đúng không, đây có phải là cách người ta có thể đạt được sự pha trộn giữa C và ASM này không? Tôi sẽ đăng trên stackoverflow cho các chi tiết cụ thể, chỉ sau một ý tưởng chung.
jwbensley

@javano: Vâng. Bạn có thể vào và ra khỏi ASM trong C. Nhiều hệ thống nhúng được viết như thế - trong hỗn hợp C và lắp ráp - chủ yếu vì có một số điều đơn giản không thể thực hiện được trong trình biên dịch C nguyên thủy có sẵn tại thời gian. Tuy nhiên, các trình biên dịch C hiện đại như gcc (là trình biên dịch được sử dụng bởi Arduino) hiện xử lý hầu hết và trong nhiều trường hợp tất cả những thứ được sử dụng để yêu cầu ngôn ngữ lắp ráp.
davidcary
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.