2011-08-08 26 views
19

Giả sử mỗi thread được thực hiện một số tính toán FP, Tôi quan tâm đếnthế nào bạn có thể đo thời gian dành cho một chuyển ngữ cảnh dưới nền tảng java

  • bao nhiêu thời gian CPU được sử dụng trong chuyển đổi bài thay vì chạy chúng
  • bao nhiêu đồng bộ hóa giao thông được tạo ra trên chia sẻ bus bộ nhớ - khi đề chia sẻ dữ liệu, họ phải sử dụng cơ chế đồng bộ

câu hỏi của tôi: làm thế nào để thiết kế một chương trình thử nghiệm để có được dữ liệu này?

Trả lời

1

bao nhiêu thời gian CPU được sử dụng trong chuyển đổi bài thay vì chạy họ

  • Hãy nói rằng bạn có 100 triệu FPU để thực hiện.
  • Tải họ trong một hàng đợi đồng bộ (ví dụ, chủ đề phải khóa hàng đợi khi bỏ phiếu)
  • Cho n là số lượng các bộ xử lý có sẵn trên thiết bị của bạn (đôi = 2, vv ...)

Sau đó tạo n luồng hút trên hàng đợi để thực hiện tất cả FPU. Bạn có thể tính tổng thời gian với System.currentTimeMillis() trước và sau. Sau đó thử với các chủ đề n + 1, sau đó n + 2, n + 3, v.v ...

Về lý thuyết, bạn càng có nhiều chủ đề, càng có nhiều chuyển đổi, thì càng mất nhiều thời gian để xử lý tất cả FPU. Nó sẽ cung cấp cho bạn một ý tưởng rất thô sơ về chi phí chuyển mạch, nhưng điều này là khó đo lường.

bao nhiêu đồng bộ hóa giao thông được tạo ra trên xe buýt bộ nhớ chia sẻ - khi đề chia sẻ dữ liệu, họ phải sử dụng cơ chế đồng bộ

tôi sẽ tạo ra 10 bài gửi mỗi 10 000 tin nhắn đến thread khác một cách ngẫu nhiên bằng cách sử dụng một hàng đợi chặn đồng bộ gồm 100 tin nhắn. Mỗi luồng sẽ xem qua hàng đợi chặn để kiểm tra xem thư có phải là thông điệp cho họ hay không và kéo nó ra nếu đúng. Sau đó, họ sẽ cố gắng đẩy một tin nhắn mà không bị chặn, sau đó lặp lại thao tác nhìn trộm, vv ... cho đến khi hàng đợi trống và tất cả các luồng đều trả về.

Trên đường đi, mỗi luồng có thể là số lần đẩy và xem/kéo thành công so với không thành công. Sau đó, bạn sẽ có một ý tưởng sơ bộ về công việc hữu ích so với công việc vô dụng trong lưu lượng đồng bộ hóa. Một lần nữa, điều này là khó đo lường.

Tất nhiên, bạn cũng có thể chơi với số chủ đề hoặc kích thước của hàng đợi chặn.

9

Bạn không thể dễ dàng phân biệt chất thải do chuyển đổi luồng và do sự tranh cãi về bộ nhớ cache. Bạn CÓ THỂ đo lường sự tranh chấp chủ đề .. Cụ thể là, trên Linux, bạn có thể cat/proc/PID/XXX và nhận được rất nhiều thống kê chi tiết cho mỗi luồng. TUY NHIÊN, vì bộ lập lịch trước sẽ không tự bắn vào chân, bạn sẽ không nhận được nhiều hơn 30 thiết bị chuyển mạch ctx mỗi giây cho dù bạn sử dụng bao nhiêu chủ đề .. Và thời gian đó sẽ tương đối nhỏ so với số lượng công việc bạn đang làm .. Chi phí thực tế của chuyển đổi ngữ cảnh là ô nhiễm bộ nhớ cache. ví dụ. có một xác suất cao mà bạn sẽ có phần lớn các cache nhớ khi bạn đã chuyển ngữ cảnh trở lại. Vì vậy, thời gian hệ điều hành và bối cảnh chuyển đổi-đếm có giá trị tối thiểu.

Giá trị thực sự có giá trị là tỷ lệ giữa các đường liên kết trong bộ nhớ cache giữa các luồng. Tùy thuộc vào CPU, một dòng bộ nhớ cache bẩn theo sau là một peer-CPU đọc là SLOWER hơn là một bộ nhớ cache-miss - bởi vì bạn phải ép buộc CPU ngang hàng để viết giá trị của nó cho mem chính trước khi bạn thậm chí có thể bắt đầu đọc .. CPU cho phép bạn kéo từ các dòng bộ nhớ cache ngang hàng mà không cần nhấn chính mem.

Vì vậy, điều quan trọng là hoàn toàn giảm thiểu BẤT CỨ cấu trúc bộ nhớ được sửa đổi chia sẻ .. Hãy làm mọi thứ như chỉ đọc nhất có thể .. BAO GỒM này chia sẻ bộ đệm FIFO (bao gồm cả nhóm điều hành) .. Cụ thể là nếu bạn đã sử dụng hàng đợi được đồng bộ hóa - thì mọi sync-op là vùng bộ nhớ bị dơ bẩn. Và nhiều hơn nữa, nếu tỷ lệ đủ cao, nó sẽ có khả năng kích hoạt một cái bẫy hệ điều hành để ngăn chặn, chờ đợi cho mutex của thread ngang hàng.

Lý tưởng là phân đoạn RAM, phân phối cho một số lượng công nhân cố định một đơn vị công việc lớn, sau đó sử dụng chốt đếm hoặc một số rào cản bộ nhớ khác (sao cho mỗi chuỗi chỉ chạm vào một lần). Lý tưởng nhất là bất kỳ bộ đệm tạm thời nào được cấp phát trước thay vì đi vào và ra khỏi một nhóm bộ nhớ dùng chung (mà sau đó gây ra sự tranh chấp bộ đệm). Java 'đồng bộ' khối đòn bẩy (đằng sau hậu trường) một không gian bộ nhớ hash-bảng chia sẻ và do đó kích hoạt không mong muốn bẩn-đọc, tôi đã không xác định nếu java 5 Khóa đối tượng tránh điều này, nhưng bạn vẫn tận dụng hệ điều hành quầy 't giúp đỡ trong thông lượng của bạn. Rõ ràng hầu hết các hoạt động OutputStream đều kích hoạt các cuộc gọi được đồng bộ hóa như vậy (và tất nhiên là thường làm đầy bộ đệm luồng chung).

Nói chung, kinh nghiệm của tôi là luồng đơn nhanh hơn việc xử lý mùn cho mảng byte-mảng/đối tượng chung, v.v. Ít nhất với các thuật toán sắp xếp/lọc đơn giản mà tôi đã thử nghiệm. Điều này đúng cả trong Java và C trong kinh nghiệm của tôi. Tôi đã không cố gắng FPU intesive ops (như phân chia, sqrt), nơi cache-dòng có thể ít yếu tố. Về cơ bản nếu bạn là một CPU duy nhất, bạn không có vấn đề về dòng bộ nhớ cache (trừ khi hệ điều hành luôn xóa bộ nhớ cache ngay cả trong các chủ đề được chia sẻ), nhưng đa luồng mua bạn ít hơn không có gì. Trong siêu phân luồng, đó là cùng một thỏa thuận. Trong cấu hình bộ nhớ cache L2/L3 được chia sẻ CPU đơn (ví dụ: AMD), bạn có thể tìm thấy một số lợi ích. Trong đa CPU Intel BUS, quên nó - chia sẻ ghi nhớ là tồi tệ hơn đơn luồng.

+0

Nếu bạn không muốn thiết kế ứng dụng, nhưng chỉ cần đo lường sự khác biệt về hiệu suất (có đọc lại câu hỏi của bạn). Sau đó, hy vọng thuật toán có thể được chia tuyến tính, sau đó được chuyển thành một số chủ đề có thể cấu hình, với 1 có thể có một đường dẫn mã thay thế đặc biệt. Sau đó, chỉ cần chạy mỗi (có thể có trước khi xuất cảnh zip up/proc/self/*). Cũng sử dụng ghi/báo cáo thời gian nano của đầu/cuối của mỗi luồng (thay vì đồng bằng của chúng). –

2

Để đo bao nhiêu thời gian một chuyển ngữ cảnh mất tôi sẽ chạy giống như sau:

public static void main(String[] args) {  
    Object theLock = new Object(); 
    long startTime; 
    long endtime; 
    synchronized(theLock){ 
     Thread task = new TheTask(theLock); 
     task.start(); 
     try { 
      theLock.wait(); 
      endTime = System.currentTimeMillis(); 
     } 
     catch(InterruptedException e){ 
      // do something if interrupted 
     } 
    } 
    System.out.println("Context Switch Time elapsed: " + endTime - startTime); 
} 

class TheTask extends Thread { 
    private Object theLock; 
    public TheTask(Object theLock){ 
     this.theLock = theLock; 
    } 
    public void run(){ 
     synchronized(theLock){ 
      startTime = System.currentTimeMillis(); 
      theLock.notify(); 
     } 
    } 
} 

Bạn có thể muốn chạy mã này nhiều lần để có được một mức trung bình và chắc chắn rằng hai chủ đề đó là những chỉ những cái chạy trong máy bạn (chuyển đổi ngữ cảnh chỉ xảy ra trong hai luồng này).

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