2009-10-06 47 views
19

Có cách nào di động cách để xác định căn chỉnh tối đa có thể cho loại nào không? Ví dụ trên x86, hướng dẫn SSE yêu cầu căn chỉnh 16 byte, nhưng theo như tôi biết, không có hướng dẫn nào đòi hỏi nhiều hơn thế, vì vậy bất kỳ loại nào có thể được lưu trữ an toàn vào bộ đệm liên kết 16 byte.Xác định căn chỉnh tối đa có thể có trong C++

Tôi cần phải tạo bộ đệm (chẳng hạn như mảng char), nơi tôi có thể viết các đối tượng thuộc loại tùy ý và vì vậy tôi cần có thể dựa vào đầu bộ đệm để căn chỉnh.

Nếu mọi thứ khác không thành công, tôi biết rằng phân bổ mảng char với new được đảm bảo có căn chỉnh tối đa, nhưng với các mẫu TR1/C++ 0x alignment_ofaligned_storage, tôi tự hỏi liệu có thể tạo bộ đệm tại chỗ trong lớp đệm của tôi, thay vì yêu cầu con trỏ thừa của một mảng được cấp động.

Ý tưởng?

Tôi nhận thấy có rất nhiều tùy chọn để xác định căn chỉnh tối đa cho một tập hợp các loại: Một công đoàn hoặc chỉ alignment_of từ TR1, nhưng vấn đề của tôi là tập hợp các loại không bị chặn. Tôi không biết trước các đối tượng nào phải được lưu vào bộ đệm.

+0

di động trong nội dung gì? cho mỗi trình biên dịch? cho từng hệ điều hành? cho mỗi kiến ​​trúc? –

+0

Chỉ cần di động như trong "được đảm bảo bởi tiêu chuẩn C++ để hoạt động". Tất nhiên, tôi có thể dễ dàng dựa vào kiến ​​thức của riêng tôi về kiến ​​trúc đích và mã hóa liên kết tối đa, nhưng sẽ tốt hơn nếu ngôn ngữ tự cung cấp các công cụ để trả lời câu hỏi này. – jalf

+3

Lưu ý rằng tham số mẫu 'Align' của' std :: aligned_storage 'có đối số mặc định là" căn chỉnh mặc định ", được định nghĩa là" Giá trị của căn chỉnh mặc định sẽ là yêu cầu căn chỉnh nghiêm ngặt nhất đối với bất kỳ đối tượng C++ nào loại có kích thước không lớn hơn 'Len'." Tôi không biết liệu các loại SSE có được coi là "loại đối tượng C++" hay không và thư viện chuẩn VC10 không có đối số mặc định, vì vậy tôi không biết giá trị dự định là gì (Tôi không có bất kỳ Thư viện chuẩn nào khác triển khai trên máy này). –

Trả lời

9

Trong C++ 0x, các Align mẫu tham số của std::aligned_storage<Len, Align> có một đối số mặc định của "mặc định-alignment", được định nghĩa là (N3225 §20.7.6.6 Bảng 56):

Giá trị của căn chỉnh mặc định là yêu cầu căn chỉnh chặt chẽ nhất đối với bất kỳ loại đối tượng C++ nào có kích thước không lớn hơn Len.

Không rõ liệu các loại SSE có được coi là "loại đối tượng C++" hay không.

Đối số mặc định không phải là một phần của TR1 aligned_storage; nó đã được thêm vào cho C++ 0x.

5

Ngắn một số maximally_aligned_t loại tất cả trình biên dịch hứa sẽ trung thành để hỗ trợ cho tất cả kiến ​​trúc ở mọi nơi, tôi không thấy cách này có thể được giải quyết tại thời gian biên dịch. Như bạn nói, tập hợp các loại tiềm năng không bị chặn. Là con trỏ thêm thực sự là một thỏa thuận lớn?

+0

Nó có thể không được, nhưng tôi tò mò nếu có một giải pháp. C++ 0x bổ sung thêm một số hàm liên quan đến liên kết khác, và việc thực hiện đã xác định sự liên kết tối đa có thể trong các trường hợp khác (khi phân bổ động mảng char) vì vậy tôi nghĩ rằng có thể có một số mẫu thư viện chuẩn bị che khuất. giá trị. – jalf

+0

Vâng. Đó là một câu hỏi thú vị, và tôi ước tôi có một câu trả lời tốt hơn cho bạn, nhưng tôi không nghĩ có cách nào phù hợp với tiêu chuẩn. maximally_aligned_t (hoặc tốt hơn, maximal_alignment) sẽ không khó thực hiện, mặc dù; có lẽ bạn nên đề xuất nó cho C++ 1x :) –

1

Phân bổ bộ nhớ liên kết là phức tạp hơn so với nó trông - xem ví dụ Implementation of aligned memory allocation

+0

Tôi biết nó khó khăn. Đó không phải là câu hỏi của tôi. ;) Nhưng tiêu chuẩn không đưa ra một số đảm bảo và đặc biệt khi bạn xem C++ 0x, bạn có một vài công cụ * chuẩn để trợ giúp. – jalf

+1

Sự phức tạp không áp dụng cho Jalf vì anh ta không phân bổ chung. Tất cả những gì anh cần là có thêm khoảng trống trong bộ đệm của mình, và làm tròn con trỏ trong bộ đệm tới khối căn chỉnh tiếp theo mong muốn. – Potatoswatter

5

Đáng tiếc là đảm bảo sự liên kết tối đa là khó khăn hơn rất nhiều so với nó phải được, và không có các giải pháp đảm bảo AFAIK. Từ GotW blog (Fast Pimpl article):

union max_align { 
    short  dummy0; 
    long  dummy1; 
    double  dummy2; 
    long double dummy3; 
    void*  dummy4; 
    /*...and pointers to functions, pointers to 
     member functions, pointers to member data, 
     pointers to classes, eye of newt, ...*/ 
}; 

union { 
    max_align m; 
    char x_[sizeofx]; 
}; 

này không đảm bảo được đầy đủ di động, nhưng trong thực tế nó là gần đủ bởi vì có rất ít hoặc không có trên hệ điều hành này sẽ không hoạt động là được mong đợi.

Đó là về 'hack' gần nhất mà tôi biết về điều này.

Có một cách tiếp cận khác mà tôi đã sử dụng cá nhân để phân bổ siêu nhanh. Lưu ý rằng nó là ác, nhưng tôi làm việc trong các lĩnh vực raytracing nơi tốc độ là một trong những biện pháp lớn nhất về chất lượng và chúng tôi hồ sơ mã trên cơ sở hàng ngày. Nó liên quan đến việc sử dụng một bộ cấp phát heap với bộ nhớ được cấp phát trước hoạt động giống như ngăn xếp cục bộ (chỉ cần tăng một con trỏ trên phân bổ và giảm một số trên deallocation).

Tôi sử dụng nó cho Pimpls đặc biệt. Tuy nhiên, chỉ có người cấp phát là không đủ; để một trình phân bổ như vậy hoạt động, chúng ta phải giả định rằng bộ nhớ cho một lớp, Foo, được cấp phát trong một hàm tạo, cùng một bộ nhớ tương tự như vậy được giải quyết chỉ trong destructor, và chính Foo đó được tạo trên stack. Để làm cho nó an toàn, tôi cần một hàm để xem liệu con trỏ 'này' của một lớp có nằm trong ngăn xếp cục bộ để xác định xem chúng ta có thể sử dụng trình phân bổ stack dựa trên đống siêu nhanh của chúng ta hay không.Để làm được điều đó, chúng tôi đã nghiên cứu các giải pháp dành riêng cho hệ điều hành: Tôi đã sử dụng TIBsTEBs cho Win32/Win64 và đồng nghiệp của tôi đã tìm thấy giải pháp cho Linux và Mac OS X.

Kết quả sau một tuần nghiên cứu cụ thể cho OS phương pháp để phát hiện phạm vi ngăn xếp, yêu cầu căn chỉnh và thực hiện rất nhiều thử nghiệm và lược tả, là một trình cấp phát có thể cấp phát bộ nhớ trong 4 chu kỳ đồng hồ theo tiêu chí đánh dấu của chúng tôi so với khoảng 400 chu kỳ cho malloc/operator new (thử nghiệm của chúng tôi liên quan sự tranh chấp chủ đề để malloc có thể nhanh hơn một chút so với trường hợp đơn luồng, có lẽ là một vài trăm chu kỳ). Chúng tôi đã thêm một chồng đống chủ đề và phát hiện chuỗi nào đang được sử dụng để tăng thời gian lên khoảng 12 chu kỳ, mặc dù khách hàng có thể theo dõi trình phân bổ chuỗi để nhận được phân bổ 4 chu kỳ. Nó đã xóa sạch các điểm phân bổ bộ nhớ dựa trên bản đồ.

Trong khi bạn không phải trải qua tất cả những rắc rối đó, việc viết cấp phát nhanh có thể dễ dàng hơn và thường áp dụng hơn (ví dụ: cho phép số lượng bộ nhớ phân bổ/deallocate được xác định trong thời gian chạy) so với một số thứ như max_align đây. max_align rất dễ sử dụng, nhưng nếu bạn đang theo tốc độ phân bổ bộ nhớ (và giả sử bạn đã lược tả mã của mình và tìm thấy điểm nóng trong malloc/free/operator new/delete với những người đóng góp chính trong mã bạn có quyền kiểm soát) , viết phân bổ của riêng bạn thực sự có thể tạo sự khác biệt.

+0

+1. Wow, phân bổ nhanh gấp 100 lần. Cảm ơn đã chia sẻ thông tin này. –

+1

Hmm, điều đó rất thú vị. Nhưng tôi đã không thực sự hỏi về phân bổ nhanh (Trong trường hợp của tôi, đó thực sự là một vấn đề khá dễ giải quyết, bởi vì tôi không phải xử lý các trường hợp khó chịu như bạn đã làm - và tôi phải nói, tôi ấn tượng bạn có nó làm việc). Nhưng câu hỏi của tôi chỉ đơn giản là đảm bảo rằng các đối tượng được phân bổ tại các địa chỉ được căn chỉnh chính xác. – jalf

+0

@ jalf Ah, xin lỗi, thông thường tôi nghĩ khi một người bắt đầu đi vào các vấn đề liên kết và lưu trữ các loại dữ liệu khác nhau vào một bộ đệm duy nhất, nó thường với một bộ nhớ cấp phát và hiệu suất trong tâm trí. Tôi e rằng tôi không biết bất kỳ cách di động nào để đảm bảo căn chỉnh tối đa cho một loại nhất định. Thông thường, tôi đã có được khá nền tảng cụ thể trong các trường hợp như vậy. Để cố gắng làm cho nó an toàn, tôi thường sử dụng phương pháp tiếp cận chọn tham gia (loại có liên kết không xác định sẽ được căn chỉnh trên các ranh giới quadword đôi, liên kết tối đa có thể tôi biết). – stinky472

-2

Đây là những gì tôi đang sử dụng. Thêm vào đó, nếu bạn đang cấp phát bộ nhớ thì mảng mảng mới() 'd có độ dài lớn hơn hoặc bằng max_alignment sẽ được căn chỉnh với max_alignment để bạn có thể sử dụng các chỉ mục vào mảng đó để lấy các địa chỉ liên kết.

enum { 
      max_alignment = boost::mpl::deref< 
       boost::mpl::max_element< 
         boost::mpl::vector< 
          boost::mpl::int_<boost::alignment_of<signed char>::value>::type, 
          boost::mpl::int_<boost::alignment_of<short int>::value>::type, 
          boost::mpl::int_<boost::alignment_of<int>::value>::type,        boost::mpl::int_<boost::alignment_of<long int>::value>::type, 
          boost::mpl::int_<boost::alignment_of<float>::value>::type, 
          boost::mpl::int_<boost::alignment_of<double>::value>::type, 
          boost::mpl::int_<boost::alignment_of<long double>::value>::type, 
          boost::mpl::int_<boost::alignment_of<void*>::value>::type 
         >::type 
        >::type 
       >::type::value 
      }; 
     } 
+0

Thật không may, điều này không đảm bảo sự liên kết phù hợp cho các loại SSE. – jalf

9

Trong C++ 11 std :: max_align_t được xác định trong tiêu đề cstddef là loại POD có yêu cầu căn chỉnh ít nhất là nghiêm ngặt (lớn) như của mọi loại vô hướng.

Sử dụng toán tử sắp xếp mới sẽ đơn giản như alignof(std::max_align_t)

+0

cho trình biên dịch không hỗ trợ alignof (tức là MSVC11), bạn có thể sử dụng std :: alignment_of :: giá trị –

+0

Điều này làm việc tuyệt vời cho đến khi có [một lỗi trong thư viện chuẩn] (https: // github .com/cameron314/concurrentqueue/issue/64): - / – Cameron

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