2011-11-01 28 views
5

Tôi đang viết trình điều khiển nhân Linux cho thiết bị USB tùy chỉnh sẽ sử dụng thiết bị đầu cuối số lượng lớn, mọi thứ dường như hoạt động tốt, tuy nhiên, tôi đang nhận được tốc độ dữ liệu rất chậm. Cụ thể, mất 25 giây để ghi và đọc dữ liệu 10MB. Tôi đã thử điều này trên một hệ thống nhúng và một máy ảo Linux chạy trên một máy tính hợp lý với kết quả tương tự.hiệu suất rất kém (~ 0,4MB/s) với trình điều khiển nhân Linux chuyển số lượng lớn và phần cứng loopback

Tôi đang sử dụng bộ phát triển EZ-USB FX2 từ Cypress làm bảng mục tiêu. Nó đang chạy chương trình cơ sở Bulkloop thiết lập hai điểm cuối trong và hai điểm cuối. Mỗi điểm cuối được đệm đôi và hỗ trợ các cửa sổ 512 byte. Firmware thăm dò điểm cuối thông qua một vòng lặp while (1) trong main(), không ngủ, và sao chép dữ liệu từ ngoài vào trong điểm cuối khi các dữ liệu đó có sẵn bằng cách sử dụng các autopointer. Tôi đã được nói rằng điều này có thể di chuyển dữ liệu khá trên Windows bằng cách sử dụng ứng dụng cụ thể của họ nhưng không có cơ hội để xác minh điều này.

Mã của tôi (các phần liên quan bên dưới) gọi một hàm gọi là bulk_io trong thường trình dò ​​tìm thiết bị. Chức năng này tạo ra một số (URB_SETS) của các urbs mà cố gắng ghi 512 byte vào thiết bị. Thay đổi số này giữa 1 và 32 không thay đổi hiệu suất. Tất cả chúng đều được sao chép từ cùng một bộ đệm. Trình xử lý gọi lại cho mỗi thao tác ghi tới một điểm đầu cuối được sử dụng để tạo ra một giá trị đã đọc trên điểm cuối tương ứng. Việc gọi lại đọc tạo ra một viết urb khác cho đến khi tôi đã đạt tổng số yêu cầu ghi/đọc mà tôi muốn chạy tại một thời điểm (20.000). Tôi hiện đang làm việc để đẩy hầu hết các hoạt động trong các chức năng gọi lại vào nửa dưới cùng trong trường hợp chúng đang chặn các ngắt khác. Tôi cũng đang nghĩ đến việc viết lại phần mềm vòng lặp số lượng lớn cho Cypress FX2 để sử dụng các ngắt thay vì bỏ phiếu. Có điều gì ở đây trông ngoài bình thường để làm cho hiệu suất quá thấp? Cảm ơn bạn trước. Xin vui lòng cho tôi biết nếu bạn muốn xem thêm mã, đây chỉ là một trình điều khiển xương trần để kiểm tra I/O cho Cypress FX2.

Đây là ra endpoint chức năng ghi callback:

static void bulk_io_out_callback0(struct urb *t_urb) { 
    // will need to make this work with bottom half 
    struct usb_dev_stat *uds = t_urb->context; 
    struct urb *urb0 = usb_alloc_urb(0,GFP_KERNEL); 
    if (urb0 == NULL) { 
      printk("bulk_io_out_callback0: out of memory!"); 
    } 
    usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_rcvbulkpipe(uds->udev,uds->ep_in[0]), uds->buf_in, uds->max_packet, bulk_io_in_callback0, uds); 
    usb_submit_urb(urb0,GFP_KERNEL); 
    usb_free_urb(urb0); 
} 

Đây là trong thiết bị đầu cuối đọc hàm callback:

static void bulk_io_in_callback0(struct urb *t_urb) { 
    struct usb_dev_stat *uds = t_urb->context; 

    struct urb *urb0 = usb_alloc_urb(0,GFP_KERNEL); 
    if (urb0 == NULL) { 
      printk("bulk_io_out_callback0: out of memory!"); 
    } 

    if (uds->seq--) { 
      usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_sndbulkpipe(uds->udev,uds->ep_out[0]), uds->buf_out, uds->max_packet, bulk_io_out_callback0, uds); 
      usb_submit_urb(urb0,GFP_KERNEL); 
    } 
    else { 
      uds->t1 = get_seconds(); 
      uds->buf_in[9] = 0; // to ensure we only print the first 8 chars below 
      printk("bulk_io_in_callback0: completed, time=%lds, bytes=%d, data=%s\n", (uds->t1-uds->t0), uds->max_packet*SEQ, uds->buf_in); 
    } 
    usb_free_urb(urb0); 
} 

Chức năng này được gọi để thiết lập URBS ban đầu:

static int bulk_io (struct usb_interface *interface, struct usb_dev_stat *uds) { 
    struct urb *urb0; 
    int i; 

    uds->t0 = get_seconds(); 

    memcpy(uds->buf_out,"abcd1234",8); 

    uds->seq = SEQ; // how many times we will run this 

    printk("bulk_io: starting up the stream, seq=%ld\n", uds->seq); 

    for (i = 0; i < URB_SETS; i++) { 
      urb0 = usb_alloc_urb(0,GFP_KERNEL); 
      if (urb0 == NULL) { 
        printk("bulk_io: out of memory!\n"); 
        return(-1); 
      } 

      usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_sndbulkpipe(uds->udev,uds->ep_out[0]), uds->buf_out, uds->max_packet, bulk_io_out_callback0, uds); 
          printk("bulk_io: submitted urb, status=%d\n", usb_submit_urb(urb0,GFP_KERNEL)); 
      usb_free_urb(urb0); // we don't need this anymore 
    } 


    return(0); 
} 

Chỉnh sửa 1 Tôi xác minh ed rằng udev-> tốc độ == 3, vì vậy USB_SPEED_HIGH, có nghĩa là đây không phải là bởi vì Linux cho rằng đây là một thiết bị chậm ....

Chỉnh sửa 2 tôi chuyển tất cả mọi thứ trong callbacks liên quan đến việc tạo ra URB (kmalloc, gửi) và giải phóng vào nửa dưới cùng, hiệu suất tương tự.

+3

Vì vậy, bí ẩn không còn nữa. Tôi đã sửa đổi firmware phần mềm CY7C68013A 'bulkloop' để chuyển đổi một GPIO khi nó đang di chuyển dữ liệu/thiết bị đầu cuối vũ trang và nó đã chi ~ 80% chu kỳ của nó làm chức năng đó. Dường như có 8051 lõi cảm ứng các bộ đệm USB ở tất cả làm giảm thông lượng đến ~ 0,5MB/s như được hiển thị ở trên. Tôi đã đi trước và điểm chuẩn với cửa sổ lib của họ CyUSB bulkloop demo và có hiệu suất tồi tệ hơn nhiều, khoảng 0.1MB/s. Tóm lại, việc sử dụng phần mềm Bulkloop không phải là một thử nghiệm tốt về hiệu suất của trình điều khiển USB. Sẽ thử nó với một FPGA ăn các dữ liệu CY7C68013A tiếp theo. – armguy

+0

chỉ là một điểm nhỏ ở đây, bạn nên giữ cho gọi lại URB càng nhỏ càng tốt (ví dụ: chỉ cần đặt cờ) –

Trả lời

1

Đọc và viết theo khối nhỏ theo kinh nghiệm của tôi không hiệu quả lắm.

Tôi đang sử dụng bộ phát triển EZ-USB FX2 từ Cypress làm bảng mục tiêu. Nó đang chạy chương trình cơ sở Bulkloop thiết lập hai điểm cuối trong và hai điểm cuối. Mỗi điểm cuối được đệm đôi và hỗ trợ các cửa sổ 512 byte.

Điều này không có nghĩa là bạn không thể ghi nhiều hơn 512 byte vào một lúc.

Tôi sẽ cố gắng viết không ít hơn 4096 byte cho nó tại một thời điểm, bởi vì đó là kích thước trang chuẩn (có lẽ không quá chuẩn trong các hệ thống nhúng).Nếu điều đó có hiệu quả, tôi sẽ cố gắng viết chừng 1/4 của một megabyte cho nó tại một thời điểm, và sau đó thậm chí nhiều hơn nếu điều đó làm việc.

Điểm mấu chốt ở đây là biết khi nào cửa sổ ghi của thiết bị đã đầy. Khi nó được - nó sẽ gọi bất cứ điều gì gọi lại, hoặc bạn nhận được thông tin đó bằng bất kỳ phương tiện nào khác và sử dụng nó trong báo hiệu ứng dụng của bạn để ngừng viết.

Lưu ý rằng cửa sổ sẽ không đầy sau khi bạn "cung cấp thiết bị" 512 byte, vì thiết bị sẽ bắt đầu đọc từ cửa sổ này ngay khi có bất cứ điều gì cần đọc.

Có lẽ tôi đã bỏ lỡ điều gì đó quan trọng trong câu hỏi của bạn, nhưng những gì tôi đang nói về cơ bản bạn phải viết nhiều hơn 512 byte cùng một lúc. Đây là lý do tại sao bạn nhận được hiệu suất kém như vậy.

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