E 'possibile rendere std::vector
delle strutture personalizzate allocare memoria allineata per un'ulteriore elaborazione con le istruzioni SIMD? Se è possibile fare con Allocator
, qualcuno può avere un simile allocatore che potrebbe condividere?Rendere std :: vector allocare memoria allineata
risposta
Modifica: Ho rimosso l'ereditarietà di std::allocator
come suggerito da GManNickG e reso il parametro di allineamento una cosa del tempo di compilazione.
Ho recentemente scritto questo pezzo di codice. Non è testato quanto vorrei, quindi vai avanti e segnala errori. :-)
enum class Alignment : size_t
{
Normal = sizeof(void*),
SSE = 16,
AVX = 32,
};
namespace detail {
void* allocate_aligned_memory(size_t align, size_t size);
void deallocate_aligned_memory(void* ptr) noexcept;
}
template <typename T, Alignment Align = Alignment::AVX>
class AlignedAllocator;
template <Alignment Align>
class AlignedAllocator<void, Align>
{
public:
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
template <class U> struct rebind { typedef AlignedAllocator<U, Align> other; };
};
template <typename T, Alignment Align>
class AlignedAllocator
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::true_type propagate_on_container_move_assignment;
template <class U>
struct rebind { typedef AlignedAllocator<U, Align> other; };
public:
AlignedAllocator() noexcept
{}
template <class U>
AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept
{}
size_type
max_size() const noexcept
{ return (size_type(~0) - size_type(Align))/sizeof(T); }
pointer
address(reference x) const noexcept
{ return std::addressof(x); }
const_pointer
address(const_reference x) const noexcept
{ return std::addressof(x); }
pointer
allocate(size_type n, typename AlignedAllocator<void, Align>::const_pointer = 0)
{
const size_type alignment = static_cast<size_type>(Align);
void* ptr = detail::allocate_aligned_memory(alignment , n * sizeof(T));
if (ptr == nullptr) {
throw std::bad_alloc();
}
return reinterpret_cast<pointer>(ptr);
}
void
deallocate(pointer p, size_type) noexcept
{ return detail::deallocate_aligned_memory(p); }
template <class U, class ...Args>
void
construct(U* p, Args&&... args)
{ ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); }
void
destroy(pointer p)
{ p->~T(); }
};
template <typename T, Alignment Align>
class AlignedAllocator<const T, Align>
{
public:
typedef T value_type;
typedef const T* pointer;
typedef const T* const_pointer;
typedef const T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::true_type propagate_on_container_move_assignment;
template <class U>
struct rebind { typedef AlignedAllocator<U, Align> other; };
public:
AlignedAllocator() noexcept
{}
template <class U>
AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept
{}
size_type
max_size() const noexcept
{ return (size_type(~0) - size_type(Align))/sizeof(T); }
const_pointer
address(const_reference x) const noexcept
{ return std::addressof(x); }
pointer
allocate(size_type n, typename AlignedAllocator<void, Align>::const_pointer = 0)
{
const size_type alignment = static_cast<size_type>(Align);
void* ptr = detail::allocate_aligned_memory(alignment , n * sizeof(T));
if (ptr == nullptr) {
throw std::bad_alloc();
}
return reinterpret_cast<pointer>(ptr);
}
void
deallocate(pointer p, size_type) noexcept
{ return detail::deallocate_aligned_memory(p); }
template <class U, class ...Args>
void
construct(U* p, Args&&... args)
{ ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); }
void
destroy(pointer p)
{ p->~T(); }
};
template <typename T, Alignment TAlign, typename U, Alignment UAlign>
inline
bool
operator== (const AlignedAllocator<T,TAlign>&, const AlignedAllocator<U, UAlign>&) noexcept
{ return TAlign == UAlign; }
template <typename T, Alignment TAlign, typename U, Alignment UAlign>
inline
bool
operator!= (const AlignedAllocator<T,TAlign>&, const AlignedAllocator<U, UAlign>&) noexcept
{ return TAlign != UAlign; }
L'implementazione per le chiamate di allocazione effettive è solo posix ma è possibile estenderla facilmente.
void*
detail::allocate_aligned_memory(size_t align, size_t size)
{
assert(align >= sizeof(void*));
assert(nail::is_power_of_two(align));
if (size == 0) {
return nullptr;
}
void* ptr = nullptr;
int rc = posix_memalign(&ptr, align, size);
if (rc != 0) {
return nullptr;
}
return ptr;
}
void
detail::deallocate_aligned_memory(void *ptr) noexcept
{
return free(ptr);
}
Esigenze C++ 11, btw.
Sì, dovrebbe essere possibile. Se si mette a questa domanda su google allora si otterrà un sacco di codice di esempio, di seguito è alcuni risultati promettenti:
Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il link per riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia.- [Dalla recensione] (/ recensione/post di bassa qualità/18787539) –
Nella prossima versione 1.56, la libreria Boost includerà Boost.Align. Tra gli altri aiuti per l'allineamento della memoria, viene fornito il codice boost::alignment::aligned_allocator
, che può essere utilizzato come sostituto drop-in per std::allocator
e consente di specificare un allineamento. Vedi la documentazione su https://boostorg.github.io/align/
È bello saperlo, ma personalmente trovo che 'boost' sia piuttosto difficile da integrare nei miei progetti (quelle librerie che non sono solo di intestazione). –
Sono d'accordo, l'integrazione di spinta può essere un po 'un dolore. Tuttavia, 'Boost.Align' _is_ solo header-only e dipende solo dalle altre librerie di sola intestazione AFAICS. – tklauser
È ora disponibile: http://www.boost.org/doc/libs/1_56_0/libs/core/doc/html/index.html – fireboot
- 1. Come allocare e liberare memoria allineata in C
- 2. Allocare correttamente memoria nel vettore
- 3. Destroy std :: vector senza rilasciare memoria
- 4. Allocazione memoria Vector C++
- 5. Huge std :: vector <std::vector> non rilascia tutta la memoria in caso di distruzione
- 6. memoria virtuale esaurita: Impossibile allocare memoria
- 7. come pre-allocare memoria per un oggetto std :: string?
- 8. restituisce memoria allineata con nuova?
- 9. std :: vector alternativa per C
- 10. Impossibile allocare memoria
- 11. mmap: Impossibile allocare memoria
- 12. Ruby: Impossibile allocare memoria
- 13. std :: list vs std :: vector iteration
- 14. Overhead to using std :: vector?
- 15. Può std :: vector essere = 'd in un altro std :: vector?
- 16. di riserva() di memoria multi-dimensionale std :: vector (C++)
- 17. Allocazione memoria attigua per diversi piccoli std :: vector?
- 18. Come rilasciare std :: vector se non c'è memoria heap
- 19. Dovrei preoccuparmi della frammentazione della memoria con std :: vector?
- 20. std :: vector swap che causa la frammentazione della memoria?
- 21. Inizializzazione Eigen :: vector con std :: vector
- 22. std :: vector or boost :: vector thread safe?
- 23. sizeof() std :: vector (C++)
- 24. Eigen e std :: vector
- 25. Ereditato da std :: vector
- 26. std :: vector di riferimenti
- 27. efficiente passaggio di std :: vector
- 28. std :: vector <std::string> crash
- 29. std :: vector più veloce di std :: unordered_set?
- 30. std :: vector di std :: vettori contiguità
hai verificato se l'allocatore standard lo fa già per te? – TemplateRex
@rhalbersma: non penso che lo faccia, non prende i parametri di allineamento. –
no, intendo: la tua implementazione STL allinea già la memoria per te? Hai calcolato l'indirizzo di memoria di 'v.begin()' e controlla se inizia con un multiplo di X byte? anche se non è possibile configurare in modo esplicito l'allineamento, lo std :: allocator potrebbe già aiutarti. – TemplateRex