numa_allocator.hpp 2.5 KB
Newer Older
Guido Novati's avatar
Guido Novati committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Example codes for HPC course
// (c) 2012 Andreas Hehn, ETH Zurich

#ifndef HPCSE_NUMA_ALLOCATOR_HPP
#define HPCSE_NUMA_ALLOCATOR_HPP

#define __CHUNKSIZE 1 // chunk size for tiled parallel for: to tune

#ifdef _WIN32
#include <malloc.h>
#endif
#include <cstdlib>

#if __cplusplus >= 201103L 
#define NOEXCEPT_SPEC noexcept
#else
#define NOEXCEPT_SPEC
#endif

namespace hpcse {

template <typename T>
class numa_allocator {
  public:
    typedef T*              pointer;
    typedef T const*        const_pointer;
    typedef T&              reference;
    typedef T const&        const_reference;
    typedef T               value_type;
    typedef std::size_t     size_type;
    typedef std::ptrdiff_t  difference_type;

    template <typename U>
    struct rebind {
        typedef numa_allocator<U> other;
    };

    numa_allocator() NOEXCEPT_SPEC {
    }

    numa_allocator(numa_allocator const& a) NOEXCEPT_SPEC {
    }

    template <typename U>
    numa_allocator(numa_allocator<U> const& b) NOEXCEPT_SPEC {
    }

    pointer allocate(size_type n) {
        void* p = malloc(n*sizeof(T));
        if(p == 0)
            throw std::bad_alloc();

        // NUMA first touch policy
        char * const pend = reinterpret_cast<char*>(p) + n*sizeof(T);

#pragma omp parallel for schedule(static)
//#pragma omp parallel for schedule(static, __CHUNKSIZE)
        for(char* p1 = reinterpret_cast<char*>(p); p1 < pend; ++p1)
            *p1 = 0;
        return reinterpret_cast<pointer>(p);
    }

    void deallocate(pointer p, size_type n) NOEXCEPT_SPEC {
        std::free(p);
    }

    size_type max_size() const NOEXCEPT_SPEC {
        std::allocator<T> a;
        return a.max_size();
    }

#if __cplusplus >= 201103L 
    template <typename C, class... Args>
    void construct(C* c, Args&&... args) {
        new ((void*)c) C(std::forward<Args>(args)...);
    }
#else
    void construct(pointer p, const_reference t) {
        new((void *)p) T(t);
    }
#endif

    template <typename C>
    void destroy(C* c) {
        c->~C();
    }

    bool operator == (numa_allocator const& a2) const NOEXCEPT_SPEC {
        return true;
    }

    bool operator != (numa_allocator const& a2) const NOEXCEPT_SPEC {
        return false;
    }

    template <typename U>
    bool operator == (numa_allocator<U> const& b) const NOEXCEPT_SPEC {
        return false;
    }

    template <typename U>
    bool operator != (numa_allocator<U> const& b) const NOEXCEPT_SPEC {
        return true;
    }
};

}

#undef NOEXPECT_SPEC

#endif //HPCSE_NUMA_ALLOCATOR_HPP