2009-03-19 10 views
11

Tôi có một ứng dụng phần mềm kế thừa yêu cầu chức năng mới. Kích thước của ứng dụng đã gần với dung lượng flash giới hạn của thiết bị và một số chức năng và biến mới đã đẩy nó lên cạnh. Bật tối ưu hóa trình biên dịch thực hiện thủ thuật, nhưng khách hàng rất thận trọng khi làm như vậy bởi vì họ đã gây ra lỗi trong quá khứ. Vì vậy, một số điều phổ biến để tìm khi tái cấu trúc mã C để sản xuất đầu ra nhỏ hơn là gì?Một số phương pháp tái cấu trúc để giảm kích thước mã được biên dịch là gì?

+0

Tôi nghĩ câu hỏi nên nói "sử dụng bộ nhớ" hoặc "kích thước đầu ra" thay vì "kích thước mã". – Angel

+0

Việc sử dụng bộ nhớ không phải là vấn đề. Đó là kích thước của hình ảnh được ghi vào bộ nhớ flash bên trong của MCU. –

+0

Tôi nghĩ rằng "kích thước của mã biên dịch" là ít mơ hồ hơn. –

Trả lời

17
  • chức năng sử dụng thế hệ thay vì bảng dữ liệu nếu có thể
  • chức năng inline Disable
  • Bật thường được sử dụng macro vào chức năng
  • Giảm độ phân giải cho các biến lớn hơn kích thước máy có nguồn gốc (tức là 8 bit vi mô, cố gắng loại bỏ biến số 16 và 32 bit - tăng gấp đôi và gấp bốn lần một số chuỗi mã)
  • Nếu vi có tập lệnh nhỏ hơn (Ngón tay cái) bật nó trong trình biên dịch
  • Nếu mem ory được phân đoạn (ví dụ, paged hoặc phi tuyến) sau đó
    • đang Sắp xếp lại để các cuộc gọi toàn cầu ít (hướng dẫn cuộc gọi lớn hơn) cần phải được sử dụng
    • đang Sắp xếp lại và sử dụng biến để loại bỏ ký ức toàn cầu cuộc gọi
    • Re- đánh giá việc sử dụng bộ nhớ toàn cầu - nếu nó có thể được đặt trên stack sau đó rất nhiều càng tốt
  • Hãy chắc chắn rằng bạn đang biên soạn với debug tắt - trên một số bộ xử lý nó làm cho một sự khác biệt lớn
  • dữ liệu
  • Compress rằng có thể không được tạo ra o n - sau đó giải nén vào ram khi khởi động để truy cập nhanh
  • Chuyển sang tùy chọn trình biên dịch - có thể là mọi cuộc gọi đều tự động toàn cầu, nhưng bạn có thể tắt an toàn trên cơ sở tệp theo tệp để giảm kích thước (đôi khi đáng kể)

Nếu bạn vẫn cần thêm không gian hơn với compile with optimizations được bật, hãy xem cụm từ được tạo với mã không được tối ưu hóa. Sau đó viết lại mã nơi các thay đổi lớn nhất đã diễn ra để trình biên dịch tạo ra các tối ưu hóa tương tự dựa trên việc viết lại C phức tạp với tối ưu hóa bị tắt.

Ví dụ, bạn có thể có nhiều 'nếu' tuyên bố rằng so sánh tương tự:

if(A && B && (C || D)){} 
if(A && !B && (C || D)){} 
if(!A && B && (C || D)){} 

Sau đó tạo một lần nữa thay đổi và làm cho một số so sánh trước sẽ tiết kiệm được trình biên dịch từ mã sao chép:

E = (C || D); 

if(A && B && E){} 
if(A && !B && E){} 
if(!A && B && E){} 

Đây là một trong những tối ưu hóa trình biên dịch thực hiện cho bạn tự động nếu bạn bật tính năng này. Có rất nhiều, nhiều người khác, và bạn có thể xem xét đọc một chút lý thuyết trình biên dịch nếu bạn muốn tìm hiểu làm thế nào để làm điều này bằng tay trong mã C.

+1

Thông báo trước duy nhất là bất kỳ quy trình nào trong các phần quan trọng trong thời gian này sẽ đảm bảo thử nghiệm bổ sung. –

+0

Tôi cho rằng tôi nên thêm tuyên bố từ chối trách nhiệm, nhưng thực tế là bất kỳ thay đổi nào dọc theo các dòng này đều là kích thước giao dịch cho hiệu suất. –

+0

Nếu bạn vô hiệu hóa các hàm nội tuyến và biến macro thành các hàm, bạn có phải tăng việc sử dụng bộ nhớ thời gian chạy hay không (nhiều hàm gọi = new stackframes). Tôi không chắc chắn về công cụ này mặc dù. – DevinB

2

Tái cấu trúc ra duplicate code sẽ có tác động lớn nhất đến bộ nhớ của chương trình.

0

Chú ý đến macro. Chúng có thể tạo ra rất nhiều mã chỉ từ một bản mở rộng macro. Nếu bạn tìm thấy các macro như vậy - hãy thử viết lại chúng để kích thước của chúng được thu nhỏ và chức năng được di chuyển đến các hàm.

Chú ý đến mã trùng lặp - cả sao chép và dán một cách hợp lý. Cố gắng tách mã trùng lặp thành các hàm.

Kiểm tra xem trình biên dịch có hỗ trợ nội tuyến và có thể tắt tính năng này hay không.

0

Tối ưu hóa trình biên dịch kích hoạt lỗi? Thật kỳ lạ. Nhận bản đồ chương trình của bạn và xem bạn có nên nhắm mục tiêu dữ liệu hoặc mã không. Tìm mã trùng lặp. Tìm mã với mục tiêu tương tự. Một ví dụ của nó là mã busybox, nhằm mục đích cho bộ nhớ nhỏ.

Đó là kích thước ưa thích so với khả năng đọc, vì vậy đôi khi nó trở nên khá xấu xí, với ảnh và vân vân.

+1

Nó không phải là không phổ biến cho các trình biên dịch nhúng để có lỗi. Chip càng ít được sử dụng rộng rãi thì trình biên dịch càng có nhiều vấn đề. Điều này ít phổ biến hơn ngày hôm nay so với thời gian trước (đặc biệt nếu gcc là trình biên dịch của bạn), nhưng nó vẫn là một lo lắng cho các nền tảng không phổ biến (ít được thử nghiệm). –

7

Nói chung: sử dụng bản đồ liên kết hoặc công cụ để tìm ra ký hiệu lớn nhất/nhiều nhất của bạn là gì, và sau đó có thể xem chúng bằng cách sử dụng bộ tách rời. Bạn sẽ ngạc nhiên với những gì bạn tìm thấy theo cách này.

Với một chút perl hoặc tương tự, bạn có thể thực hiện công việc ngắn của tệp .xMAP hoặc kết quả của "objdump" hoặc "nm" và sắp xếp lại theo nhiều cách khác nhau để có thông tin thích hợp.


Cụ thể cho các bộ chỉ dẫn nhỏ: Xem literal pool cách sử dụng. Trong khi thay đổi từ ví dụ: hướng dẫn ARM (32 bit cho mỗi lệnh) được đặt thành bộ chỉ lệnh THUMB (16 bit mỗi lệnh) có thể hữu ích trên một số bộ xử lý ARM, nó làm giảm kích thước của trường "ngay lập tức".

Đột nhiên thứ gì đó sẽ là tải trực tiếp từ toàn cầu hoặc tĩnh trở nên rất gián tiếp; trước tiên nó phải tải địa chỉ của global/static vào thanh ghi, sau đó tải từ đó, thay vì chỉ mã hóa địa chỉ trực tiếp trong lệnh. Vì vậy, bạn sẽ nhận được một vài hướng dẫn bổ sung một mục nhập bổ sung trong hồ bơi theo nghĩa đen cho thứ gì đó thông thường sẽ là một hướng dẫn.

Một chiến lược để chống lại điều này là nhóm các hình cầu và thống kê lại thành các cấu trúc; theo cách này, bạn chỉ lưu trữ một chữ (địa chỉ của cấu trúc toàn cầu của bạn) và tính toán bù trừ từ đó, thay vì lưu trữ nhiều chữ khác nhau khi bạn truy cập nhiều số liệu thống kê/hình cầu.

Chúng tôi chuyển đổi các lớp "singleton" của chúng tôi từ việc quản lý con trỏ cá thể của riêng mình thành thành viên trong "cấu trúc GlobalTable" và tạo sự khác biệt đáng kể về kích thước mã (vài phần trăm) cũng như hiệu suất trong một số trường hợp .


Nếu không: hãy theo dõi các cấu trúc tĩnh và mảng dữ liệu không được xây dựng một cách không cần thiết. Mỗi một trong số này thường tạo ra một lượng lớn mã .sinit ("các hàm vô hình", nếu bạn muốn) được chạy trước main() để điền các mảng này đúng cách. Nếu bạn chỉ có thể sử dụng các loại dữ liệu tầm thường trong các thống kê của mình, bạn sẽ tốt hơn rất nhiều.

Đây là một cái gì đó có thể dễ dàng xác định bằng cách sử dụng một công cụ trên kết quả của "nm" hoặc "objdump" hoặc tương tự. Nếu bạn có một tấn công cụ .sinit, bạn sẽ muốn điều tra!


Ồ, và - nếu trình biên dịch/trình liên kết của bạn hỗ trợ, đừng ngại bật tối ưu hóa hoặc tập lệnh nhỏ hơn chỉ cho một số tệp hoặc chức năng nhất định!

+0

+1 Cách tiếp cận cao su đáp ứng tốt. –

+0

+1 Tệp bản đồ liên kết là nơi bắt đầu. Nó sẽ cho bạn thấy nơi không gian đang được sử dụng. –

0

Các câu trả lời ở trên khẳng định "Bật tối ưu hóa trình biên dịch [giảm kích thước mã]".Với tất cả các tài liệu và kinh nghiệm tôi đã có trong các hệ thống nhúng lập trình TI DSP, tôi biết thực tế là bật tối ưu hóa sẽ TĂNG kích thước mã của bạn (đối với chip TI DSP)!


Hãy để tôi giải thích:

Các TI TMSCx6416 DSP có 9 cờ biên dịch sẽ ảnh hưởng đến kích thước mã của bạn.

  1. 3 lá cờ khác nhau cho Tối ưu hóa
  2. 3 lá cờ khác nhau cho Debugging
  3. 3 lá cờ khác nhau cho Mã kích thước

Đối với trình biên dịch của tôi, khi bạn bật mức độ tối ưu hóa ba các bang tài liệu:

  1. Tự động nội tuyến cho một số chức năng nhất định sẽ xảy ra -> sẽ tăng kích thước mã
  2. Phần mềm pipelining được bật -> sẽ tăng kích thước mã

Phần mềm pipelining là gì?

Đó là nơi trình biên dịch sẽ thực hiện mọi thứ trong assembly, giúp cho các vòng lặp hoạt động nhanh hơn đáng kể (nhanh hơn tới vài lần) nhưng với chi phí cỡ mã lớn hơn. Tôi khuyên bạn nên đọc khoảng software pipelining at wikipedia (tìm vòng lặp unrolling, prolog, và epilog).

Vì vậy, hãy kiểm tra tài liệu của bạn để đảm bảo tối ưu hóa không làm cho mã của bạn lớn hơn.


Một đề xuất khác là tìm kiếm cờ trình biên dịch có liên quan đến kích thước mã. Nếu bạn có cờ trình biên dịch kích thước mã, hãy đảm bảo tăng tốc độ lên đến cài đặt cao nhất. Thông thường biên dịch cho kích thước mã có nghĩa là mã của bạn sẽ thực thi chậm hơn ... nhưng bạn có thể phải làm điều đó.

+0

Sử dụng tối ưu hóa mức cao cho kích thước IAR EW430 cho mục tiêu TI MSP430 đã làm giảm kích thước mã được biên dịch, nhưng đó không phải là giải pháp mà tôi đã chọn. –

+0

Nhìn vào các cờ biên dịch mà tùy chọn tạo ra, vô hiệu hóa nội tuyến và bỏ vòng lặp nằm trong số đó. Đó là những hành động đã được ghi nhận trong các câu trả lời hiện tại. –

+0

Có vẻ như sự cố của bạn đã được giải quyết. Đối với sự tò mò của riêng tôi, trong trình biên dịch của bạn bật tối ưu hóa dẫn đến vô hiệu hóa inline/loop unrolling/etc? –