Ưu điểm và nhược điểm của HugePages

Ưu điểm và nhược điểm của HugePages

Dịch bài viết chuẩn bị cho học viên khóa học "Quản trị viên Linux".

Trước đây, tôi đã nói về cách kiểm tra và kích hoạt Hugepages trên Linux.
Bài viết này sẽ chỉ hữu ích nếu bạn thực sự có một nơi để sử dụng Hugepages. Tôi đã gặp rất nhiều người bị đánh lừa bởi viễn cảnh rằng Hugepages sẽ cải thiện năng suất một cách kỳ diệu. Tuy nhiên, phân trang lớn là một chủ đề phức tạp và có thể làm giảm hiệu suất nếu sử dụng không đúng cách.

Phần 1: Xác minh rằng các trang khổng lồ đã được bật trên Linux (bản gốc đây)

Vấn đề:
Bạn cần kiểm tra xem HugePages có được bật trên hệ thống của bạn hay không.

giải pháp:
Nó khá đơn giản:

cat /sys/kernel/mm/transparent_hugepage/enabled

Bạn sẽ nhận được một cái gì đó như thế này:

always [madvise] never

Bạn sẽ thấy một danh sách các tùy chọn có sẵn (luôn luôn, madvise, không bao giờ) và tùy chọn hiện đang hoạt động sẽ được đặt trong dấu ngoặc đơn (theo mặc định mavis).

mavis có nghĩa là transparent hugepages chỉ được bật cho các vùng bộ nhớ yêu cầu rõ ràng các trang lớn bằng cách sử dụng madvise (2).

luôn luôn có nghĩa là transparent hugepages luôn được kích hoạt cho tất cả các tiến trình. Điều này thường cải thiện hiệu suất, nhưng nếu bạn gặp trường hợp sử dụng trong đó nhiều tiến trình đang tiêu thụ một lượng nhỏ bộ nhớ thì tổng tải bộ nhớ có thể tăng đáng kể.

không bao giờ có nghĩa là transparent hugepages sẽ không được đưa vào ngay cả khi được yêu cầu sử dụng madvise. Để tìm hiểu thêm, liên hệ tài liệu Hạt nhân Linux.

Cách thay đổi giá trị mặc định

Tùy chọn 1: Thay đổi trực tiếp sysfs (sau khi khởi động lại tham số sẽ trở về giá trị mặc định):

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

Tùy chọn 2: Thay đổi mặc định của hệ thống bằng cách biên dịch lại kernel với cấu hình đã sửa đổi (tùy chọn này chỉ được khuyến nghị nếu bạn đang sử dụng kernel tùy chỉnh):

  • Để luôn đặt theo mặc định, hãy sử dụng:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Để đặt madvise làm mặc định, hãy sử dụng:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Phần 2: Ưu điểm và nhược điểm của HugePages

Chúng tôi sẽ cố gắng giải thích có chọn lọc những ưu điểm, nhược điểm và những cạm bẫy có thể xảy ra khi sử dụng Hugepages. Vì một bài viết phức tạp về mặt công nghệ và mang tính mô phạm có thể sẽ khó hiểu đối với những người bị ảo tưởng rằng Hugepages là một loại thuốc chữa bách bệnh, nên tôi sẽ hy sinh tính chính xác để lấy sự đơn giản. Điều đáng lưu ý là rất nhiều chủ đề thực sự phức tạp và do đó được đơn giản hóa rất nhiều.

Xin lưu ý rằng chúng ta đang nói về các hệ thống x64 86-bit chạy Linux và tôi chỉ đơn giản giả định rằng hệ thống này hỗ trợ các trang lớn trong suốt (vì việc các trang khổng lồ không bị ghi đè không phải là bất lợi), như trường hợp của hầu hết mọi Linux hiện đại. môi trường.

Tôi sẽ đính kèm thêm mô tả kỹ thuật trong các liên kết bên dưới.

Bộ nhớ ảo

Nếu bạn là lập trình viên C++, bạn biết rằng các đối tượng trong bộ nhớ có địa chỉ cụ thể (giá trị con trỏ).

Tuy nhiên, những địa chỉ này không nhất thiết phản ánh địa chỉ vật lý trong bộ nhớ (địa chỉ RAM). Chúng đại diện cho các địa chỉ trong bộ nhớ ảo. Bộ xử lý có mô-đun MMU (đơn vị quản lý bộ nhớ) đặc biệt giúp nhân ánh xạ bộ nhớ ảo tới một vị trí thực tế.

Cách tiếp cận này có nhiều ưu điểm, nhưng những ưu điểm quan trọng nhất là:

  • Hiệu suất (vì nhiều lý do);
  • Cách ly chương trình, nghĩa là không chương trình nào có thể đọc được từ bộ nhớ của chương trình khác.

Trang là gì?

Bộ nhớ ảo được chia thành các trang. Mỗi trang riêng lẻ trỏ đến một bộ nhớ vật lý cụ thể, nó có thể trỏ đến một vùng trong RAM hoặc có thể trỏ đến một địa chỉ được gán cho thiết bị vật lý, chẳng hạn như thẻ video.

Hầu hết các trang bạn xử lý đều trỏ đến RAM hoặc được hoán đổi, nghĩa là chúng được lưu trữ trên ổ cứng hoặc SSD của bạn. Kernel quản lý bố cục vật lý của mỗi trang. Nếu một trang giả mạo được truy cập, kernel sẽ dừng luồng đang cố truy cập vào bộ nhớ, đọc trang từ ổ cứng/SSD vào RAM rồi tiếp tục thực thi luồng đó.

Quá trình này diễn ra trong suốt, nghĩa là nó không nhất thiết phải đọc trực tiếp từ HDD/SSD. Kích thước của trang bình thường là 4096 byte. Kích thước trang lớn là 2 megabyte.

Bộ đệm liên kết dịch thuật (TLB)

Khi một chương trình truy cập vào một trang bộ nhớ, CPU phải biết trang vật lý nào để đọc dữ liệu từ đó (nghĩa là có bản đồ địa chỉ ảo).

Nhân có cấu trúc dữ liệu (bảng trang) chứa tất cả thông tin về các trang đang được sử dụng. Sử dụng cấu trúc dữ liệu này, bạn có thể ánh xạ địa chỉ ảo sang địa chỉ vật lý.

Tuy nhiên, bảng trang khá phức tạp và chậm nên chúng ta không thể phân tích toàn bộ cấu trúc dữ liệu mỗi khi một tiến trình truy cập vào bộ nhớ.

May mắn thay, bộ xử lý của chúng tôi có TLB lưu trữ ánh xạ giữa địa chỉ ảo và địa chỉ vật lý. Điều này có nghĩa là mặc dù chúng ta cần phân tích bảng trang trong lần truy cập đầu tiên, nhưng tất cả các lần truy cập tiếp theo vào trang có thể được xử lý trong TLB, cho phép hoạt động nhanh chóng.

Bởi vì nó được triển khai như một thiết bị vật lý (làm cho nó hoạt động nhanh ngay từ đầu) nên dung lượng của nó bị hạn chế. Vì vậy, nếu bạn muốn truy cập nhiều trang hơn, TLB sẽ không thể lưu trữ ánh xạ cho tất cả các trang đó, khiến chương trình của bạn chạy chậm hơn nhiều.

Hugepages đến giải cứu

Vậy chúng ta có thể làm gì để tránh tình trạng tràn TLB? (Chúng tôi cho rằng chương trình vẫn cần cùng một lượng bộ nhớ).

Đây là lúc Hugepages xuất hiện. Thay vì 4096 byte chỉ yêu cầu một mục nhập TLB, một mục nhập TLB giờ đây có thể trỏ đến con số khổng lồ là 2 megabyte. Giả sử TLB có 512 mục, ở đây không có trang lớn, chúng tôi có thể khớp:

4096 b⋅512=2 MB

Vậy thì làm sao chúng ta có thể so sánh với họ:

2 MB⋅512=1 GB

Đây là lý do tại sao Hugepages thật tuyệt vời. Họ có thể cải thiện năng suất mà không cần nỗ lực nhiều. Nhưng có những cảnh báo quan trọng ở đây.

Hugepages giả mạo

Kernel tự động giám sát tần suất mỗi trang bộ nhớ được sử dụng. Nếu không có đủ bộ nhớ vật lý (RAM), kernel sẽ di chuyển các trang ít quan trọng hơn (ít được sử dụng hơn) vào đĩa cứng để giải phóng một số RAM cho các trang quan trọng hơn.
Về nguyên tắc, điều tương tự cũng áp dụng cho Hugepages. Tuy nhiên, kernel chỉ có thể trao đổi toàn bộ trang chứ không phải từng byte riêng lẻ.

Giả sử chúng ta có một chương trình như thế này:

char* mymemory = malloc(2*1024*1024); // Возьмем это за одну Hugepage!
// Заполним mymemory какими-либо данными
// Сделаем много других вещей,
// которые приведут к подмене страницы mymemory
// ...
// Запросим доступ только к первому байту
putchar(mymemory[0]); 

Trong trường hợp này, kernel sẽ cần thay thế (đọc) tối đa 2 megabyte thông tin từ ổ cứng/SSD chỉ để bạn đọc được một byte. Đối với các trang thông thường, chỉ cần đọc 4096 byte từ ổ cứng/SSD.

Do đó, nếu trang lớn bị ghi đè, việc đọc chỉ nhanh hơn nếu bạn cần truy cập toàn bộ trang. Điều này có nghĩa là nếu bạn đang cố truy cập ngẫu nhiên các phần khác nhau của bộ nhớ và chỉ đọc vài kilobyte, bạn nên sử dụng các trang thông thường và không phải lo lắng về bất kỳ điều gì khác.

Mặt khác, nếu bạn cần truy cập tuần tự một phần lớn bộ nhớ, các trang lớn sẽ cải thiện hiệu suất của bạn. Tuy nhiên, bạn cần phải tự mình kiểm tra nó (không phải bằng phần mềm trừu tượng) và xem cái nào hoạt động nhanh hơn.

Phân bổ trong bộ nhớ

Nếu bạn viết C, bạn biết rằng bạn có thể yêu cầu lượng bộ nhớ nhỏ (hoặc gần như lớn tùy ý) từ heap bằng cách sử dụng malloc(). Giả sử bạn cần 30 byte bộ nhớ:

char* mymemory = malloc(30);

Đối với một lập trình viên, có vẻ như bạn đang “yêu cầu” 30 byte bộ nhớ từ hệ điều hành và trả về một con trỏ tới bộ nhớ ảo nào đó. Nhưng trên thực tế malloc () chỉ là một hàm C gọi từ bên trong hàm brk và sbrk để yêu cầu hoặc giải phóng bộ nhớ khỏi hệ điều hành.

Tuy nhiên, việc yêu cầu ngày càng nhiều bộ nhớ cho mỗi lần phân bổ là không hiệu quả; rất có thể một số phân đoạn bộ nhớ đã được giải phóng (free())và chúng ta có thể tái sử dụng nó. malloc() thực hiện các thuật toán khá phức tạp để sử dụng lại bộ nhớ đã giải phóng.

Đồng thời, mọi thứ diễn ra mà bạn không hề hay biết, vậy tại sao nó lại khiến bạn lo lắng? Nhưng vì thử thách free() không có nghĩa là vậy bộ nhớ nhất thiết phải được trả lại ngay lập tức cho hệ điều hành.

Có một thứ gọi là sự phân mảnh bộ nhớ. Trong những trường hợp đặc biệt, có những phân đoạn heap chỉ sử dụng một vài byte, trong khi mọi thứ ở giữa đều được giải phóng. (free()).

Xin lưu ý rằng phân mảnh bộ nhớ là một chủ đề cực kỳ phức tạp và ngay cả những thay đổi nhỏ đối với chương trình cũng có thể có tác động đáng kể. Trong hầu hết các trường hợp, các chương trình sẽ không gây ra sự phân mảnh bộ nhớ đáng kể, nhưng bạn nên lưu ý rằng nếu có vấn đề về phân mảnh ở một số khu vực của heap, thì các trang khổng lồ có thể khiến tình hình trở nên tồi tệ hơn.

Sử dụng có chọn lọc các trang lớn

Sau khi đọc bài viết này, bạn đã xác định được phần nào trong chương trình của mình có thể hưởng lợi từ việc sử dụng Hugepages và phần nào thì không. Vì vậy, các trang khổng lồ có nên được kích hoạt không?

May mắn thay, bạn có thể sử dụng madvise()chỉ kích hoạt tính năng phân trang lớn cho những vùng bộ nhớ mà nó sẽ hữu ích.

Trước tiên, hãy kiểm tra xem các trang lớn có đang chạy ở chế độ madvise() hay không bằng cách sử dụng hướng dẫn ở đầu bài viết.

Sau đó sử dụng madvise()để cho kernel biết chính xác nơi sử dụng Hugepages.

#include <sys/mman.h>
// Аллоцируйте большое количество памяти, которую будете использовать
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// Просто включите hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … и задайте следующее
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)

Lưu ý rằng phương pháp này chỉ đơn giản là lời khuyên cho kernel về cách quản lý bộ nhớ. Điều này không có nghĩa là kernel sẽ tự động sử dụng các trang lớn cho một bộ nhớ nhất định.

Tham khảo tài liệu (manpage)điên cuồngđể tìm hiểu thêm về quản lý bộ nhớ và madvise(), chủ đề này có một đường cong học tập cực kỳ dốc. Vì vậy, nếu bạn có ý định thực sự giỏi về nó, hãy chuẩn bị đọc và kiểm tra trong vài tuần trước khi bạn mong đợi bất kỳ kết quả tích cực nào.

Đọc gì?

Có một câu hỏi? Viết trong các ý kiến!

Nguồn: www.habr.com

Thêm một lời nhận xét