2009-03-19 45 views
50

Tôi có thể hiểu cách người ta có thể viết chương trình sử dụng nhiều quy trình hoặc chủ đề: fork() một quy trình mới và sử dụng IPC, hoặc tạo nhiều chủ đề và sử dụng các loại cơ chế giao tiếp đó.Làm cách nào để kiểm soát quy trình cốt lõi nào đang chạy?

Tôi cũng hiểu ngữ cảnh chuyển đổi. Tức là, chỉ với một lần CPU, hệ điều hành sẽ lên lịch thời gian cho mỗi tiến trình (và có rất nhiều thuật toán lên lịch) và do đó chúng tôi đạt được nhiều tiến trình đồng thời.

Và bây giờ chúng tôi có bộ xử lý đa lõi (hoặc máy tính đa xử lý), chúng tôi có thể có hai quy trình chạy đồng thời trên hai lõi riêng biệt.

Câu hỏi của tôi là về kịch bản cuối cùng: kiểm soát hạt nhân mà một quá trình cốt lõi chạy như thế nào? Các cuộc gọi hệ thống nào (trong Linux, hoặc thậm chí Windows) lên lịch trình cho một lõi cụ thể?

Lý do tôi hỏi: Tôi đang làm việc trong một dự án cho trường học nơi chúng tôi đang tìm hiểu một chủ đề gần đây về tính toán - và tôi đã chọn kiến ​​trúc đa lõi. Dường như có rất nhiều tài liệu về cách lập trình trong loại môi trường đó (cách xem các bế tắc hoặc điều kiện chủng tộc) nhưng không nhiều về việc kiểm soát các lõi riêng lẻ. Tôi rất thích có thể viết một vài chương trình trình diễn và trình bày một số hướng dẫn lắp ráp hoặc mã C cho hiệu ứng "Xem, tôi đang chạy vòng lặp vô hạn trên lõi thứ 2, nhìn vào mức sử dụng CPU cho lõi cụ thể đó ".

Bất kỳ ví dụ mã nào? Hoặc hướng dẫn?

chỉnh sửa: Để làm rõ - nhiều người đã nói rằng đây là mục đích của HĐH và người đó nên để hệ điều hành xử lý việc này. Tôi hoàn toàn đồng ý! Nhưng sau đó những gì tôi yêu cầu (hoặc cố gắng để có được một cảm giác cho) là những gì hệ điều hành thực sự không làm điều này. Không phải thuật toán lập lịch, nhưng nhiều hơn "một khi một lõi được chọn, những hướng dẫn nào phải được thực hiện để có các hướng dẫn lấy lõi bắt đầu?"

+1

câu trả lời có thể ở đây: http://stackoverflow.com/questions/980999/what-does-multicore-assembly-language-look-like, một trong những câu trả lời mô tả Interruptor Interruptor Interruptor, được gửi từ lõi CPU tới APIC của chipset, và có thể được sử dụng để khởi tạo một CPU khác và chạy mã trên đó CPU tại một địa chỉ cụ thể –

+0

Ví dụ tối thiểu bắt đầu SMP trong hệ điều hành của chính chúng ta: http://stackoverflow.com/a/33651438/895245 Chơi với bộ nhớ + đồng bộ hóa đó sẽ là cách. –

Trả lời

31

Như những người khác đã đề cập, mối quan hệ của bộ vi xử lý là Hệ điều hành cụ thể. Nếu bạn muốn làm điều này bên ngoài giới hạn của hệ điều hành, bạn đang ở trong rất nhiều niềm vui, và do đó tôi có nghĩa là đau đớn.

Điều đó nói rằng, những người khác đã đề cập đến SetProcessAffinityMask cho Win32. Không ai đề cập đến cách nhân Linux để thiết lập ái lực của bộ vi xử lý, và vì vậy tôi sẽ làm như vậy. Bạn cần sử dụng chức năng sched_set_affinity. Đây là a nice tutorial về cách thực hiện.

+1

Tôi đã viết một bài báo về chủ đề này một thời gian, nhưng nó được viết bằng tiếng Slovak, vì vậy tôi đoán điều đó sẽ không giúp người đó hỏi :) Dù sao, câu trả lời của bạn đi đúng hướng, vì vậy tôi deffo cho bạn phiếu bầu lên :-) –

+0

Hướng dẫn đó đặt mặt nạ sở thích thành "created_thread", trong đó, AFAICT, không nói đúng cpu khi luồng hiện đang chạy. Nó chỉ là một số nguyên được tăng lên và sử dụng theo cách như vậy để lập chỉ mục vào bitmap, nhưng có vẻ như trong ví dụ không có xác định thực sự của bộ xử lý hiện đang được sử dụng, chỉ giới hạn các tiến trình con chạy trên cpu # tương ứng với thứ tự mà các tiến trình con được tạo ra. – Jotorious

1

Hệ điều hành biết cách thực hiện việc này, bạn không phải làm như vậy. Bạn có thể chạy vào tất cả các loại vấn đề nếu bạn chỉ định lõi nào để chạy, một số trong đó có thể thực sự làm chậm quá trình. Hãy để hệ điều hành con số nó ra, bạn chỉ cần bắt đầu chủ đề mới. Ví dụ, nếu bạn đã nói với một quá trình bắt đầu trên lõi x, nhưng lõi x đã chịu tải nặng, bạn sẽ tồi tệ hơn nếu bạn chỉ cho phép hệ điều hành xử lý nó.

+0

có, tôi upvoted, nhưng có lẽ bạn có một quá trình chạy và bạn muốn bắt đầu quá trình B, C, và D trên bất kỳ lõi, ngoại trừ một chạy A. có vẻ hoàn toàn hợp lý. –

30

Thông thường quyết định về ứng dụng cốt lõi nào sẽ chạy trên hệ thống. Tuy nhiên, bạn có thể đặt "ái lực" cho ứng dụng thành một lõi cụ thể để thông báo cho hệ điều hành chỉ chạy ứng dụng trên lõi đó. Thông thường đây không phải là một ý tưởng tốt, nhưng có một số trường hợp hiếm hoi mà nó có thể có ý nghĩa.

Để thực hiện việc này trong cửa sổ, hãy sử dụng trình quản lý tác vụ, nhấp chuột phải vào quy trình và chọn "Đặt mối quan hệ". Bạn có thể làm điều đó theo lập trình trong Windows bằng cách sử dụng các hàm như SetThreadAffinityMask, SetProcessAffinityMask hoặc SetThreadIdealProcessor.

ETA:

Nếu bạn quan tâm đến cách hệ điều hành thực sự nào để lập kế hoạch, bạn có thể muốn kiểm tra những liên kết này:

Wikipedia article on context switching

Wikipedia article on scheduling

Scheduling in the linux kernel

Với hầu hết các hệ điều hành hiện đại, hệ điều hành sẽ lên lịch một luồng để thực thi trên lõi một lát thời gian ngắn. Khi lát thời gian hết hạn, hoặc thread thực hiện một hoạt động IO khiến nó tự nguyện lấy lõi, hệ điều hành sẽ lên lịch một luồng khác để chạy trên lõi (nếu có bất kỳ luồng nào sẵn sàng chạy). Chính xác luồng nào được lên lịch phụ thuộc vào thuật toán lập lịch của hệ điều hành.

Chi tiết triển khai chính xác cách chuyển đổi bối cảnh xảy ra là phụ thuộc vào hệ điều hành CPU &. Nó thường sẽ liên quan đến một chuyển đổi sang chế độ hạt nhân, hệ điều hành tiết kiệm trạng thái của chủ đề trước đó, tải trạng thái của chủ đề mới, sau đó chuyển về chế độ người dùng và tiếp tục lại chuỗi mới tải. Bài viết chuyển ngữ cảnh mà tôi đã liên kết ở trên có một chút chi tiết hơn về điều này.

+0

+1 để cung cấp cách dễ dàng để thực hiện. –

+0

Lưu ý rằng mặt nạ ái lực được thừa hưởng bởi các tiến trình con, vì vậy nếu bạn đặt nó trên Explorer, tất cả các ứng dụng được khởi chạy cũng sẽ sử dụng một tập con của các bộ xử lý có sẵn. – Richard

1

Tôi không biết hướng dẫn lắp ráp. Nhưng chức năng API của cửa sổ là SetProcessAffinityMask. Bạn có thể xem an example thứ gì đó tôi đã rải sỏi cùng lúc trước để chạy Picasa chỉ trên một lõi

2

Như những người khác đã đề cập, nó được điều khiển bởi hệ điều hành. Tùy thuộc vào hệ điều hành, nó có thể hoặc có thể không cung cấp cho bạn các cuộc gọi hệ thống cho phép bạn ảnh hưởng đến lõi nào mà một quá trình đã cho thực thi. Tuy nhiên, bạn thường chỉ nên để hệ điều hành thực hiện hành vi mặc định. Nếu bạn có một hệ thống 4 nhân với 37 quy trình đang chạy và 34 trong số các quy trình đó đang ngủ, nó sẽ lên lịch cho 3 quy trình hoạt động còn lại trên các lõi riêng biệt.

Bạn sẽ chỉ thấy tăng tốc khi chơi với các mối quan hệ cốt lõi trong các ứng dụng đa luồng rất chuyên dụng. Ví dụ, giả sử bạn có một hệ thống với 2 bộ xử lý lõi kép. Giả sử bạn có một ứng dụng có 3 luồng và hai luồng hoạt động mạnh trên cùng một tập hợp dữ liệu, trong khi luồng thứ ba sử dụng một tập dữ liệu khác. Trong trường hợp này, bạn sẽ được hưởng lợi nhiều nhất bằng cách có hai luồng tương tác trên cùng một bộ xử lý và luồng thứ ba trên bộ xử lý khác, kể từ đó chúng có thể chia sẻ bộ đệm. Hệ điều hành không có ý tưởng về bộ nhớ mà mỗi thread cần truy cập, vì vậy nó có thể không phân bổ các luồng tới lõi một cách thích hợp.

Nếu bạn quan tâm đến cách hệ điều hành, hãy đọc trên scheduling. Các chi tiết gritty nitty của đa xử lý trên x86 có thể được tìm thấy trong Intel 64 and IA-32 Architectures Software Developer's Manuals. Tập 3A, Chương 7 và 8 chứa thông tin liên quan, nhưng lưu ý những hướng dẫn này cực kỳ kỹ thuật.

3

Dự án OpenMPIlibrary to set the processor affinity trên Linux theo cách di động.

Một số khi trở lại, tôi đã sử dụng điều này trong một dự án và nó hoạt động tốt.

Nhớ lại: Tôi nhớ một số vấn đề trong việc tìm hiểu cách hệ điều hành đếm số lõi. Tôi sử dụng điều này trong một hệ thống CPU 2 Xeon với 4 lõi mỗi.

Nhìn vào cat /proc/cpuinfo có thể hữu ích. Trên chiếc hộp tôi đã sử dụng, nó khá lạ. Luộc xuống đầu ra là ở cuối.

Rõ ràng, các lõi được đánh số đồng đều nằm trên cpu đầu tiên và các số được đánh số lẻ nằm trên cpu thứ hai. Tuy nhiên, nếu tôi nhớ chính xác, đã xảy ra sự cố với bộ đệm. Trên các bộ xử lý Intel Xeon này, hai lõi trên mỗi CPU chia sẻ cache L2 của chúng (tôi không nhớ bộ xử lý có bộ đệm L3) hay không. Tôi nghĩ rằng các bộ vi xử lý ảo 0 và 2 chia sẻ một bộ nhớ cache L2, 1 và 3 chia sẻ một, 4 và 6 chia sẻ một và 5 và 7 chia sẻ một.

Vì sự kỳ quặc này (1,5 năm trước tôi không thể tìm thấy bất kỳ tài liệu nào về quá trình đánh số trong Linux), tôi sẽ cẩn thận thực hiện loại điều chỉnh mức thấp này. Tuy nhiên, rõ ràng là một số công dụng. Nếu mã của bạn chạy trên một vài loại máy thì có thể bạn nên thực hiện loại điều chỉnh này. Một ứng dụng khác sẽ có trong một số ngôn ngữ cụ thể của miền như StreamIt nơi trình biên dịch có thể thực hiện công việc bẩn này và tính toán một lịch trình thông minh.

processor  : 0 
physical id  : 0 
siblings  : 4 
core id   : 0 
cpu cores  : 4 

processor  : 1 
physical id  : 1 
siblings  : 4 
core id   : 0 
cpu cores  : 4 

processor  : 2 
physical id  : 0 
siblings  : 4 
core id   : 1 
cpu cores  : 4 

processor  : 3 
physical id  : 1 
siblings  : 4 
core id   : 1 
cpu cores  : 4 

processor  : 4 
physical id  : 0 
siblings  : 4 
core id   : 2 
cpu cores  : 4 

processor  : 5 
physical id  : 1 
siblings  : 4 
core id   : 2 
cpu cores  : 4 

processor  : 6 
physical id  : 0 
siblings  : 4 
core id   : 3 
cpu cores  : 4 

processor  : 7 
physical id  : 1 
siblings  : 4 
core id   : 3 
cpu cores  : 4 
+0

SLERT cũng cố gắng này và có cơ chế khá tinh vi để lựa chọn một bộ xử lý hoặc nhóm xử lý. –

5

Không có gì cho lõi "bây giờ bắt đầu chạy quá trình này".

Phần lõi không thấy quy trình, nó chỉ biết về mã thực thi và các mức chạy khác nhau và giới hạn liên quan đến hướng dẫn có thể được thực thi.

Khi máy tính khởi động, vì mục đích đơn giản, chỉ một lõi/bộ xử lý hoạt động và thực sự chạy bất kỳ mã nào. Sau đó, nếu hệ điều hành là MultiProcessor có khả năng, nó kích hoạt lõi khác với một số hướng dẫn cụ thể hệ thống, lõi khác rất có thể nhận từ chính xác cùng một chỗ như lõi khác và chạy từ đó.

Vì vậy, công cụ lập lịch biểu trông như thế nào thông qua cấu trúc bên trong hệ điều hành (nhiệm vụ/quy trình/chuỗi chủ đề) và chọn một và đánh dấu nó là chạy ở lõi của nó. Sau đó, các thể hiện lịch trình khác chạy trên các lõi khác sẽ không chạm vào nó cho đến khi nhiệm vụ đang ở trạng thái đợi lần nữa (và không được đánh dấu là được ghim vào lõi cụ thể). Sau khi tác vụ được đánh dấu là đang chạy, trình lập lịch thực hiện chuyển sang vùng người dùng với nhiệm vụ tiếp tục tại điểm mà nó đã bị treo trước đó. Về mặt kỹ thuật, không có gì ngăn lõi chạy chính xác cùng một mã tại cùng một thời điểm chính xác (và nhiều chức năng mở khóa), nhưng trừ khi mã được viết để mong đợi, nó có thể sẽ tự chảy ra.

Kịch bản trở nên kỳ quặc với các mẫu bộ nhớ kỳ lạ hơn (ở trên giả định không gian bộ nhớ đơn tuyến tính "thông thường) mà lõi không nhất thiết phải nhìn thấy cùng một bộ nhớ và có thể có yêu cầu tìm nạp mã từ các bộ ly hợp của lõi khác dễ dàng xử lý hơn bằng cách đơn giản giữ nhiệm vụ được gắn vào lõi (kiến trúc AFAIK Sony PS3 với SPU giống như thế).

1

Để tìm ra số của bộ vi xử lý thay vì sử dụng/proc/cpuinfo chỉ cần chạy:

nproc 

Để chạy một quá trình trên một nhóm các bộ xử lý cụ thể:

taskset --cpu-list 1,2 my_command 

sẽ nói rằng tôi lệnh chỉ có thể chạy trên cpu 1 hoặc 2.

Để chạy chương trình trên 4 bộ xử lý thực hiện 4 việc khác nhau, hãy sử dụng tham số hóa. Đối số cho chương trình nói với nó để làm một cái gì đó khác nhau:

for i in `seq 0 1 3`; 
do 
    taskset --cpu-list $i my_command $i; 
done 

Một ví dụ tốt về điều này là đối phó với 8 triệu hoạt động trong một mảng để từ 0 đến (2 triệu-1) đi vào bộ vi xử lý 1, 2 triệu đến (4mil-1) để xử lý 2 và cứ tiếp tục như vậy.

Bạn có thể ghé qua tải trên mỗi quá trình bằng cách cài đặt htop sử dụng apt-get/yum và chạy ở dòng lệnh:

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