2012-06-27 20 views
10

Tôi đã thực hiện ứng dụng tính toán chuyên sâu bằng cách sử dụng OpenCV cho iOS. Tất nhiên là chậm. Nhưng nó chậm hơn 200 lần so với nguyên mẫu PC của tôi. Vì vậy, tôi đã tối ưu hóa nó xuống. Từ 15 giây đầu tiên, tôi đã có thể đạt được tốc độ 0,4 giây. Tôi tự hỏi nếu tôi tìm thấy tất cả mọi thứ và những gì người khác có thể muốn chia sẻ. Những gì tôi đã làm:Tốc độ tối đa từ IOS/iPad/iPhone

  1. Thay thế "double" loại dữ liệu bên trong OpenCV thành "float". Double là 64bit và 32bit CPU không thể dễ dàng xử lý chúng, vì vậy float đã cho tôi một số tốc độ. OpenCV sử dụng gấp đôi rất thường xuyên.

  2. Đã thêm "-mpfu=neon" vào tùy chọn trình biên dịch. Tác dụng phụ là vấn đề mới mà trình biên dịch giả lập không hoạt động nữa và mọi thứ có thể được kiểm tra chỉ trên phần cứng riêng.

  3. Thay thế sin()cos() triển khai với 90 bảng tra cứu giá trị. Tăng tốc rất lớn! Điều này là phần nào đối diện với PC, nơi tối ưu hóa như vậy không cung cấp cho bất kỳ tăng tốc. Có mã hoạt động theo độ và giá trị này được chuyển đổi thành radian cho sin()cos(). Mã này cũng đã bị xóa. Nhưng các bảng tra cứu đã thực hiện công việc.

  4. Đã bật "thumb optimizations". Một số bài đăng trên blog đề xuất chính xác nhưng điều này là do ngón tay cái khiến mọi thứ thường chậm hơn trên armv6. armv7 không có bất kỳ vấn đề gì và làm mọi việc nhanh hơn và nhỏ hơn.

  5. Để đảm bảo tối ưu hóa ngón tay cái và -mfpu=neon hoạt động tốt nhất và không giới thiệu các sự cố, tôi đã xóa hoàn toàn mục tiêu armv6. Tất cả mã của tôi được biên dịch thành armv7 và điều này cũng được liệt kê là yêu cầu trong cửa hàng ứng dụng. Điều này có nghĩa là tối thiểu iPhone sẽ là 3GS. Tôi nghĩ rằng nó là OK để thả những người lớn tuổi. Dù sao những cái cũ có CPU chậm hơn và ứng dụng chuyên sâu CPU cung cấp trải nghiệm người dùng xấu nếu được cài đặt trên thiết bị cũ.

  6. Dĩ nhiên tôi sử dụng -O3 flag

  7. Tôi đã xóa "dead code" từ OpenCV. Thường thì khi tối ưu hóa OpenCV tôi thấy mã rõ ràng là không cần thiết cho dự án của tôi. Ví dụ thường có thêm "if()" để kiểm tra kích thước pixel là 8 bit hoặc 32 bit và tôi biết rằng tôi chỉ cần 8bit. Điều này loại bỏ một số mã, cung cấp trình tối ưu hóa cơ hội tốt hơn để loại bỏ một cái gì đó nhiều hơn hoặc thay thế bằng các hằng số. Ngoài ra mã phù hợp tốt hơn vào bộ nhớ cache.

Bất kỳ thủ thuật và ý tưởng nào khác? Đối với tôi cho phép ngón tay cái và thay thế lượng giác với tra cứu đã thúc đẩy các nhà sản xuất và làm tôi ngạc nhiên. Có lẽ bạn biết một cái gì đó nhiều hơn để làm mà làm cho các ứng dụng bay?

Trả lời

13

Nếu bạn đang thực hiện nhiều phép tính dấu chấm động, nó sẽ có lợi cho bạn rất nhiều khi sử dụng khung công tác Accelerate của Apple. Nó được thiết kế để sử dụng phần cứng dấu chấm động để thực hiện các phép tính trên các vectơ song song.

Tôi cũng sẽ đề cập đến điểm của bạn từng người một:

1) Đây là không phải vì CPU, đó là vì tính đến ARMv7 thời chỉ 32-bit hoạt động điểm nổi sẽ được tính toán trong nổi phần cứng xử lý điểm (vì apple đã thay thế phần cứng). Các bit 64 bit sẽ được tính toán trong phần mềm thay thế. Đổi lại, các hoạt động 32 bit nhanh hơn rất nhiều.

2) NEON là tên của bộ chỉ dẫn bộ xử lý dấu phẩy động mới

3) Có, đây là phương pháp nổi tiếng. Một cách khác là sử dụng khung công tác của Apple mà tôi đã đề cập ở trên. Nó cung cấp các hàm sin và cos tính toán 4 giá trị song song. Các thuật toán được tinh chỉnh trong lắp ráp và NEON để chúng mang lại hiệu suất tối đa trong khi sử dụng pin tối thiểu.

4) Việc triển khai ARM77 mới không có những hạn chế của armv6. Đề xuất vô hiệu chỉ áp dụng cho v6.

5) Có, xem xét 80% người dùng trên iOS 5.0 trở lên hiện nay (thiết bị armv6 đã kết thúc hỗ trợ tại 4.2.1), điều này hoàn toàn có thể chấp nhận được đối với hầu hết các trường hợp.

6) Điều này xảy ra tự động khi bạn xây dựng trong chế độ phát hành.

7) Có, điều này sẽ không có tác dụng lớn như các phương pháp trên.

Đề xuất của tôi là để kiểm tra Tăng tốc. Bằng cách đó bạn có thể chắc chắn rằng bạn đang tận dụng toàn bộ sức mạnh của bộ xử lý dấu chấm động.

+0

Gia tốc này mới đối với tôi. Nó vẫn còn chút khó khăn để sử dụng vì nó cần mức độ lắp ráp của tư duy. Nhưng vẫn có thể và có thể sẽ thử. Tôi đánh dấu nó được chấp nhận sau này vì tôi muốn xem liệu chúng ta có gợi ý hữu ích hơn ở đây không. –

+1

Có một phiên trong các video WWDC 2012 đề cập hoàn toàn với khung Tăng tốc. Bạn nên xem qua nó ^^ – borrrden

+0

http://adcdownload.apple.com//wwdc_2012/wwdc_2012_session_pdfs/session_708__the_accelerate_framework.pdf và https://developer.apple.com/videos/wwdc/2012/#708 dường như để được liên kết cho nó –

1

Tôi cung cấp một số phản hồi cho các bài đăng trước. Điều này giải thích một số ý tưởng tôi đã cố gắng để cung cấp về mã chết tại điểm 7. Điều này có nghĩa là một ý tưởng rộng hơn một chút. Tôi cần định dạng, vì vậy không thể sử dụng biểu mẫu nhận xét. Mã như vậy là trong OpenCV:

for(kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++) { 
    vec[kk] = 0; 
} 

Tôi muốn xem nó trông như thế nào trên lắp ráp. Để chắc chắn rằng tôi có thể tìm thấy nó trong lắp ráp, tôi bọc nó như thế này:

__asm__("#start"); 
for(kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++) { 
    vec[kk] = 0; 
} 
__asm__("#stop"); 

Bây giờ tôi nhấn "Sản phẩm -> Generate Output -> tập hội" và những gì tôi nhận được là:

@ InlineAsm Start 
    #start 
    @ InlineAsm End 
Ltmp1915: 
    ldr r0, [sp, #84] 
    movs r1, #0 
    ldr r0, [r0, #16] 
    ldr r0, [r0, #28] 
    cmp r0, #4 
    mov r0, r4 
    blo LBB14_71 
LBB14_70: 
Ltmp1916: 
    ldr r3, [sp, #84] 
    movs r2, #0 
Ltmp1917: 
    str r2, [r0], #4 
    adds r1, #1 
Ltmp1918: 
Ltmp1919: 
    ldr r2, [r3, #16] 
    ldr r2, [r2, #28] 
    lsrs r2, r2, #2 
    cmp r2, r1 
    bgt LBB14_70 
LBB14_71: 
Ltmp1920: 
    add.w r0, r4, #8 
    @ InlineAsm Start 
    #stop 
    @ InlineAsm End 

Rất nhiều mã. Tôi printf-d ra giá trị của (int)(descriptors->elem_size/sizeof(vec[0])) và nó đã luôn 64. Vì vậy, tôi hardcoded nó là 64 và thông qua một lần nữa thông qua lắp ráp:

@ InlineAsm Start 
    #start 
    @ InlineAsm End 
Ltmp1915: 
    vldr.32 s16, LCPI14_7 
    mov r0, r4 
    movs r1, #0 
    mov.w r2, #256 
    blx _memset 
    @ InlineAsm Start 
    #stop 
    @ InlineAsm End 

Như bạn có thể thấy bây giờ ưu đã có ý tưởng và mã trở nên ngắn hơn nhiều. Nó đã có thể vector hóa điều này. Điểm là trình biên dịch luôn luôn không biết những gì đầu vào là hằng số nếu đây là một cái gì đó giống như kích thước máy ảnh webcam hoặc độ sâu pixel nhưng trong thực tế trong bối cảnh của tôi họ thường xuyên và tất cả tôi quan tâm là tốc độ.

Tôi cũng đã cố gắng tăng tốc như đề nghị thay thế ba dòng với:

__asm__("#start"); 
vDSP_vclr(vec,1,64); 
__asm__("#stop"); 

hội bây giờ trông:

@ InlineAsm Start 
    #start 
    @ InlineAsm End 
Ltmp1917: 
    str r1, [r7, #-140] 
Ltmp1459: 
Ltmp1918: 
    movs r1, #1 
    movs r2, #64 
    blx _vDSP_vclr 
Ltmp1460: 
Ltmp1919: 
    add.w r0, r4, #8 
    @ InlineAsm Start 
    #stop 
    @ InlineAsm End 

Không chắc chắn nếu điều này là nhanh hơn so với bzero mặc dù. Trong bối cảnh của tôi, phần này không có nhiều thời gian và hai biến thể dường như hoạt động ở cùng một tốc độ.

Một điều nữa tôi học được là sử dụng GPU. Thông tin thêm tại đây http://www.sunsetlakesoftware.com/2012/02/12/introducing-gpuimage-framework

Các vấn đề liên quan