Cách tiếp cận hiện đại để tạo std :: vector phân bổ bộ nhớ căn chỉnh


11

Câu hỏi sau đây có liên quan, tuy nhiên câu trả lời đã cũ và nhận xét từ người dùng Marc Glisse cho thấy có những cách tiếp cận mới kể từ C ++ 17 cho vấn đề này có thể không được thảo luận đầy đủ.

Tôi đang cố gắng để bộ nhớ được căn chỉnh hoạt động chính xác cho SIMD, trong khi vẫn có quyền truy cập vào tất cả dữ liệu.

Trên Intel, nếu tôi tạo một vectơ nổi loại __m256và giảm kích thước của tôi xuống 8 lần, nó sẽ cho tôi bộ nhớ căn chỉnh.

Ví dụ std::vector<__m256> mvec_a((N*M)/8);

Theo một cách hơi khó hiểu, tôi có thể truyền con trỏ đến các phần tử vectơ để nổi, cho phép tôi truy cập các giá trị float riêng lẻ.

Thay vào đó, tôi muốn có một std::vector<float>cái được căn chỉnh chính xác, và do đó có thể được tải vào __m256và các loại SIMD khác mà không bị lỗi.

Tôi đã xem xét căn chỉnh_alloc .

Điều này có thể cho tôi một mảng kiểu C được căn chỉnh chính xác:

auto align_sz = static_cast<std::size_t> (32);
float* marr_a = (float*)aligned_alloc(align_sz, N*M*sizeof(float));

Tuy nhiên tôi không chắc làm thế nào để làm điều này cho std::vector<float>. Trao std::vector<float>quyền sở hữu marr_a dường như là không thể .

Tôi đã thấy một số gợi ý rằng tôi nên viết một công cụ cấp phát tùy chỉnh , nhưng điều này có vẻ như rất nhiều công việc, và có lẽ với C ++ hiện đại, có cách nào tốt hơn không?


1
không có segfaulting ... hoặc không có sự chậm trễ tiềm ẩn từ các phân tách dòng bộ đệm khi bạn sử dụng _mm256_loadu_ps(&vec[i]). (Mặc dù lưu ý rằng với các tùy chọn điều chỉnh mặc định, GCC chia tách không bảo lãnh canh 256-bit tải / cửa hàng vào vmovups XMM / vinsertf128. Vì vậy, có một lợi thế để sử dụng _mm256_loadtrên loadunếu bạn quan tâm về cách biên dịch mã của bạn trên GCC nếu quên một người nào đó sử dụng -mtune=...hoặc -march=tùy chọn.)
Peter Cordes

Câu trả lời:


1

Tất cả các bộ chứa trong thư viện C ++ tiêu chuẩn, bao gồm các vectơ, có một tham số mẫu tùy chọn chỉ định bộ cấp phát của bộ chứa và thực sự không có nhiều công việc để thực hiện cái riêng của bạn:

class my_awesome_allocator {
};

std::vector<float, my_awesome_allocator> awesomely_allocated_vector;

Bạn sẽ phải viết một ít mã thực hiện phân bổ của mình, nhưng nó sẽ không nhiều mã hơn bạn đã viết. Nếu bạn không cần hỗ trợ trước C ++ 17, bạn chỉ cần thực hiện các phương thức allocate ()deallocate () , đó là nó.


Họ cũng cần phải chuyên môn hóaallocator_traits
NathanOliver

1
Đây có thể là một nơi tốt cho một câu trả lời chính tắc với một ví dụ mà mọi người có thể sao chép / dán để nhảy qua các vòng lặp khó chịu của C ++. (Điểm thưởng nếu có cách để std :: vector cố gắng phân bổ lại tại chỗ thay vì bản in thông thường C ++ luôn phân bổ + sao chép.) Tất nhiên cũng lưu ý rằng điều này vector<float, MAA>không tương thích với loại vector<float>(và không thể vì bất cứ thứ gì được biên dịch .push_backđơn giản std::vector<float>mà không có bộ cấp phát này đều có thể thực hiện phân bổ mới và sao chép vào bộ nhớ được căn chỉnh tối thiểu. Và mới / xóa không tương thích với căn chỉnh_alloc / miễn phí)
Peter Cordes

1
Tôi không nghĩ có bất kỳ đảm bảo nào rằng con trỏ được trả về từ bộ cấp phát được sử dụng trực tiếp làm địa chỉ cơ sở của std::vectormảng. Ví dụ, tôi có thể tưởng tượng việc triển khai std::vectorchỉ sử dụng một con trỏ vào bộ nhớ được phân bổ lưu trữ phần cuối / dung lượng / cấp phát trong bộ nhớ trước phạm vi giá trị. Điều đó có thể dễ dàng ngăn chặn sự liên kết được thực hiện bởi người cấp phát.
Dietmar Kühl

1
Ngoại trừ việc std::vectorđảm bảo nó. Đó là những gì nó sử dụng nó cho. Có lẽ bạn nên xem lại những gì tiêu chuẩn C ++ chỉ định ở đây.
Sam Varshavchik

1
> Họ cũng cần chuyên môn hóa allocator_traits- Không, họ không. Tất cả những gì cần thiết là để thực hiện một phân bổ tuân thủ.
Andrey Semashev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.