đơn giản thay đổi trình biên dịch có thể cải thiện hiệu suất C của bạn cho cùng một mã nguồn nhiều lần. GCC đã không nhất thiết phải nhận được tốt hơn cho hiệu suất trong những năm qua, đối với một số chương trình gcc 3.x sản xuất mã chặt chẽ hơn 4.x. Quay lại khi tôi có quyền truy cập vào các công cụ, trình biên dịch ARM tạo ra mã tốt hơn đáng kể so với gcc. Nhanh gấp 3 đến 4 lần. LLVM đã bắt kịp với GCC 4.x và tôi nghi ngờ sẽ vượt qua gcc theo hiệu suất và sử dụng tổng thể cho việc biên dịch chéo mã nhúng. Hãy thử các phiên bản khác nhau của gcc, 3.x và 4.x nếu bạn đang sử dụng gcc. Metaware của trình biên dịch và cánh tay adt chạy vòng tròn xung quanh gcc3.x, gcc3.x sẽ cung cấp cho gcc4.xa chạy cho tiền của mình với mã cánh tay, cho mã ngón tay cái gcc4.x là tốt hơn và cho thumb2 (mà doesnt áp dụng cho bạn) gcc4.x cũng tốt hơn. Hãy nhớ rằng tôi đã không nói một từ về việc thay đổi một dòng mã (chưa).
LLVM có khả năng tối ưu hóa toàn bộ chương trình ngoài các núm điều chỉnh vô hạn hơn gcc. Mặc dù mã được tạo ra (ver 27) chỉ là bắt kịp với gcc 4.x hiện tại về hiệu suất cho một vài chương trình mà tôi đã thử.Và tôi đã không thử kết hợp tối ưu hóa thực tế (tối ưu hóa bước biên dịch, các tùy chọn khác nhau cho mỗi tệp hoặc kết hợp hai tệp hoặc ba tệp hoặc tất cả các tệp và tối ưu hóa các gói đó, lý thuyết của tôi không tối ưu hóa từ C đến bc bước, liên kết tất cả các bc với nhau sau đó làm một tối ưu hóa duy nhất vượt qua trên toàn bộ chương trình, cho phép tối ưu hóa mặc định khi llc đưa nó đến mục tiêu).
Bằng cùng một mã thông báo, chỉ cần biết trình biên dịch của bạn và tối ưu hóa có thể cải thiện đáng kể hiệu suất của mã mà không phải thay đổi bất kỳ mã nào. Bạn có một ARM11 arr bạn biên dịch cho arm11 hoặc chung cánh tay? Bạn có thể đạt được một vài đến một chục phần trăm bằng cách nói cho trình biên dịch cụ thể mà kiến trúc/gia đình (armv6 ví dụ) trên armv4 chung (ARM7) thường được chọn làm mặc định. Biết sử dụng -O2 hoặc -O3 nếu bạn dũng cảm.
Nó thường không phải là trường hợp, nhưng chuyển sang chế độ ngón tay cái có thể cải thiện hiệu suất cho nền tảng cụ thể. Không áp dụng cho bạn, nhưng sự thăng tiến của game thủ là một ví dụ hoàn hảo, được tải với các trạng thái chờ 16 bit khác. Ngón tay cái có một số tiền trên chi phí phần trăm vì cần nhiều hướng dẫn hơn để làm điều tương tự, nhưng bằng cách tăng thời gian tìm nạp và tận dụng một số tính năng đọc tuần tự của mã ngón tay cái có thể chạy nhanh hơn đáng kể so với mã cánh tay cho cùng một mã nguồn.
có arm11 bạn có thể có L1 và bộ nhớ cache L2 có thể đang bật? Chúng có được cấu hình không? Bạn có một mmu và bộ nhớ sử dụng nặng của bạn được lưu trữ? hoặc là bạn đang chạy không chờ đợi bộ nhớ nhà nước và không cần một bộ nhớ cache và nên tắt nó đi? Ngoài việc không nhận ra rằng bạn có thể lấy cùng mã nguồn và làm cho nó chạy nhanh hơn nhiều lần bằng cách thay đổi các trình biên dịch hoặc tùy chọn, mọi người thường không nhận ra rằng khi bạn sử dụng bộ nhớ đệm, chỉ cần thêm một lần lên một vài bước trong mã khởi động của bạn (như là một mẹo để điều chỉnh nơi mã đất trong bộ nhớ bằng một, hai, một vài từ) bạn có thể thay đổi tốc độ thực thi mã của bạn bằng 10 đến 20 phần trăm. Nơi mà các dòng bộ nhớ cache đọc hit trong các chức năng được sử dụng rất nhiều/vòng làm cho một sự khác biệt lớn. Thậm chí tiết kiệm một dòng bộ nhớ cache đọc bằng cách điều chỉnh nơi mã đất là đáng chú ý (cắt nó từ 3 đến 2 hoặc 2-1 ví dụ).
Biết kiến trúc của bạn, cả bộ xử lý và môi trường bộ nhớ của bạn là nơi điều chỉnh nếu có bất kỳ khởi động nào. Hầu hết các thư viện C nếu bạn đủ cao để sử dụng một thư viện (tôi thường không sử dụng thư viện C khi chạy mà không có hệ điều hành và tài nguyên rất hạn chế) cả trong mã C và đôi khi thêm một số trình biên dịch để thực hiện các thủ tục tắc nghẽn như memcpy, nhanh hơn nhiều. Nếu các chương trình của bạn hoạt động trên 32 hoặc thậm chí tốt hơn địa chỉ 64 bit, và bạn điều chỉnh ngay cả khi nó có nghĩa là sử dụng một số byte nhiều bộ nhớ hơn cho mỗi cấu trúc/mảng/memcpy thành một bội số của 32 bit hoặc 64 bit bạn sẽ thấy cải tiến đáng chú ý (nếu mã của bạn sử dụng cấu trúc hoặc sao chép dữ liệu theo những cách khác). Ngoài việc nhận được cấu trúc của bạn (nếu bạn sử dụng chúng, tôi chắc chắn không có mã nhúng), ngay cả khi bạn lãng phí bộ nhớ, nhận các phần tử được căn chỉnh, hãy cân nhắc sử dụng các số nguyên 32 bit cho mỗi phần tử thay vì byte hoặc halfwords. Tùy thuộc vào hệ thống bộ nhớ của bạn điều này có thể giúp (nó có thể làm tổn thương quá btw). Như với ví dụ GBA ở trên nhìn vào các hàm cụ thể mà bằng cách lược tả hoặc trực giác, bạn biết không được triển khai theo cách tận dụng bộ xử lý hoặc nền tảng hoặc thư viện bạn có thể muốn chuyển sang trình biên dịch hoặc từ đầu hoặc biên dịch từ C ban đầu sau đó tháo và điều chỉnh tay. Memcpy là một ví dụ tốt, bạn có thể biết hiệu năng bộ nhớ hệ thống của bạn và có thể chọn để tạo riêng memcpy của bạn đặc biệt cho dữ liệu liên kết, sao chép 64 hoặc 128 hoặc nhiều bit cho mỗi hướng dẫn.
Tương tự, trộn các biến toàn cầu và cục bộ có thể tạo ra sự khác biệt hiệu suất đáng chú ý. Theo truyền thống, người ta không bao giờ sử dụng globals, nhưng trong nhúng này không nhất thiết phải đúng, phụ thuộc vào mức độ nhúng sâu và bao nhiêu điều chỉnh và tốc độ và các yếu tố khác mà bạn quan tâm. Đây là một chủ đề nhạy cảm và tôi có thể bị quấy rầy vì nó, Tôi sẽ để nó ở đó.
Trình biên dịch phải ghi và xóa sổ đăng ký để thực hiện cuộc gọi hàm, cộng với nếu bạn sử dụng biến cục bộ, có thể cần có khung ngăn xếp, vì vậy cuộc gọi hàm rất tốn kém, nhưng đồng thời, tùy thuộc vào mã trong chức năng hiện đã tăng kích thước bằng cách tránh các hàm, bạn có thể tạo ra sự cố mà bạn đang cố gắng tránh, xóa sổ đăng ký để sử dụng lại chúng. Ngay cả một dòng mã C có thể tạo sự khác biệt giữa tất cả các biến trong một hàm phù hợp trong sổ đăng ký để bắt đầu gỡ bỏ một loạt các thanh ghi. Đối với các chức năng hoặc phân đoạn của mã mà bạn biết bạn cần một số biên dịch hiệu suất được biên dịch và tháo rời (và xem xét việc sử dụng đăng ký, tần suất nó tải bộ nhớ hoặc ghi vào bộ nhớ). Bạn có thể và sẽ tìm thấy những nơi mà bạn cần phải sử dụng một vòng lặp được sử dụng tốt và làm cho nó trở thành chức năng riêng của nó mặc dù lời gọi hàm có một hình phạt bởi vì làm như vậy trình biên dịch có thể tối ưu hóa tốt hơn vòng lặp và không gỡ bỏ/đăng ký lại. tổng lợi nhuận ròng. Ngay cả một hướng dẫn thêm trong một vòng lặp mà đi xung quanh hàng trăm lần là một hit hiệu suất đo lường.
Hy vọng rằng bạn đã biết hoàn toàn không biên dịch để gỡ lỗi, hãy tắt tất cả các biên dịch cho các tùy chọn gỡ lỗi. Bạn có thể đã biết rằng mã biên dịch để gỡ lỗi chạy mà không có lỗi không có nghĩa là nó được sửa lỗi, biên dịch để gỡ rối và sử dụng các trình gỡ rối ẩn các lỗi để chúng như các quả bom thời gian trong mã của bạn để biên dịch cuối cùng của bạn để phát hành. Tìm hiểu để luôn luôn biên dịch cho phát hành và thử nghiệm với phiên bản phát hành cho cả hiệu suất và tìm lỗi trong mã của bạn.
Hầu hết các bộ lệnh không có chức năng phân chia. Tránh sử dụng phân chia hoặc modulo trong mã của bạn càng nhiều càng tốt, chúng có thể là những kẻ giết người thực hiện. Đương nhiên đây không phải là trường hợp cho quyền hạn của hai, để lưu trình biên dịch và tinh thần tránh chia và modulos cố gắng sử dụng ca và ands. Multplies dễ dàng hơn và thường được tìm thấy trong các tập lệnh, nhưng vẫn tốn kém. Đây là một trường hợp tốt để viết assembler để làm nhân của bạn thay vì để cho C copiler làm điều đó. Các cánh tay nhân là 32bit * 32bit = 32 bit để làm toán chính xác mà không tràn phải có thêm mã C bọc xung quanh nhân, nếu bạn đã biết bạn sẽ không tràn, ghi các đăng ký cho một cuộc gọi chức năng và làm nhân trong lắp ráp (cho cánh tay).
Tương tự như vậy, hầu hết các bộ lệnh không có một đơn vị dấu chấm động, với bạn có thể, ngay cả như vậy tránh nổi nếu có thể. Nếu bạn phải sử dụng float, đó là một hộp toàn bộ các vấn đề hiệu suất của pandora khác. Hầu hết mọi người không nhìn thấy các vấn đề hiệu suất với mã đơn giản như này:
float a,b;
...
a = b * 7.0;
Phần còn lại của vấn đề là không hiểu nổi chính xác điểm và làm thế nào tốt hay xấu các thư viện C chỉ là cố gắng để có được hằng số của bạn thành điểm nổi hình thức. Một lần nữa float là một cuộc thảo luận dài khác về các vấn đề hiệu năng.
Tôi là sản phẩm của Michael Abrash (Tôi thực sự có bản sao zen của ngôn ngữ lắp ráp) và dòng dưới cùng là thời gian mã của bạn. Hãy tìm ra một cách chính xác để mã hóa thời gian, bạn có thể nghĩ rằng bạn biết các nút cổ chai ở đâu và bạn có thể nghĩ rằng bạn biết kiến trúc của mình, nhưng hãy thử những thứ khác nhau ngay cả khi bạn nghĩ chúng sai, và định thời gian cho chúng. tìm ra lỗi trong suy nghĩ của bạn. Khi bước điều chỉnh cuối cùng là một ví dụ tốt về điều này, tất cả công việc khác bạn đã thực hiện cho hiệu năng có thể bị xóa ngay lập tức bởi không có sự liên kết tốt với bộ đệm, điều này cũng có nghĩa là sắp xếp lại các chức năng trong mã nguồn để chúng hạ cánh ở các vị trí khác nhau trong hình ảnh nhị phân. Tôi đã thấy 10 đến 20 phần trăm thay đổi tốc độ tăng và giảm như là kết quả của sự sắp xếp đường bộ nhớ cache.
Có hệ điều hành nào không? Nó là gì? Bạn đang sử dụng trình biên dịch/chuỗi công cụ nào? Bạn có GPIO phụ tùng? Bạn có mô phỏng làm việc không? _Embedded_ là một lĩnh vực lớn. – nategoose