bulk.hpp 9.39 KB
Newer Older
Matthieu Dorier's avatar
Matthieu Dorier committed
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * (C) 2017 The University of Chicago
 * 
 * See COPYRIGHT in top-level directory.
 */
#ifndef __THALLIUM_BULK_HPP
#define __THALLIUM_BULK_HPP

#include <cstdint>
#include <string>
#include <vector>
#include <margo.h>
#include <thallium/endpoint.hpp>
14
#include <thallium/margo_exception.hpp>
Matthieu Dorier's avatar
Matthieu Dorier committed
15 16 17 18

namespace thallium {

class engine;
Matthieu Dorier's avatar
Matthieu Dorier committed
19
class remote_bulk;
Matthieu Dorier's avatar
Matthieu Dorier committed
20

Matthieu Dorier's avatar
Matthieu Dorier committed
21 22 23 24 25
/**
 * @brief bulk objects represent abstractions of memory
 * segments exposed by a process for RDMA operations. A bulk
 * object can be serialized to be sent over RPC to another process.
 */
Matthieu Dorier's avatar
Matthieu Dorier committed
26 27 28
class bulk {

    friend class engine;
Matthieu Dorier's avatar
Matthieu Dorier committed
29
    friend class remote_bulk;
Matthieu Dorier's avatar
Matthieu Dorier committed
30 31 32 33 34 35

private:

    engine*   m_engine;
	hg_bulk_t m_bulk;
    bool      m_is_local;
Matthieu Dorier's avatar
Matthieu Dorier committed
36
    bool      m_eager_mode;
Matthieu Dorier's avatar
Matthieu Dorier committed
37

Matthieu Dorier's avatar
Matthieu Dorier committed
38 39 40 41 42 43 44 45 46 47
    /**
     * @brief Constructor. Made private as bulk objects
     * are instanciated by engine::expose (for example),
     * not directory by users.
     *
     * @param e Reference to the engine instance creating the object.
     * @param b Mercury bulk handle.
     * @param local Whether the bulk handle referes to memory that is
     * local to this process.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
48
	bulk(engine& e, hg_bulk_t b, bool local)
Matthieu Dorier's avatar
Matthieu Dorier committed
49
	: m_engine(&e), m_bulk(b), m_is_local(local), m_eager_mode(false) {}
Matthieu Dorier's avatar
Matthieu Dorier committed
50

Matthieu Dorier's avatar
Matthieu Dorier committed
51 52 53 54
    /**
     * @brief The bulk_segment class represents a portion
     * (represented by offset and size) of a bulk object.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
55 56
    class bulk_segment {

Matthieu Dorier's avatar
Matthieu Dorier committed
57
        friend class remote_bulk;
Matthieu Dorier's avatar
Matthieu Dorier committed
58 59 60 61 62 63 64
        
        std::size_t m_offset;
        std::size_t m_size;
        const bulk& m_bulk;

        public:

Matthieu Dorier's avatar
Matthieu Dorier committed
65 66 67 68 69 70
        /**
         * @brief Constructor. By default the size of the segment will be
         * that of the underlying bulk object, and the offset is 0.
         *
         * @param b Reference to the bulk object from which the segment is taken.
         */
Matthieu Dorier's avatar
Matthieu Dorier committed
71 72 73
        bulk_segment(const bulk& b)
        : m_offset(0), m_size(b.size()), m_bulk(b) {}

Matthieu Dorier's avatar
Matthieu Dorier committed
74 75 76 77 78 79 80
        /**
         * @brief Constructor.
         *
         * @param b Reference to the bulk object from which the segment is taken.
         * @param offset Offset at which the segment starts.
         * @param size Size of the segment.
         */
Matthieu Dorier's avatar
Matthieu Dorier committed
81 82 83
        bulk_segment(const bulk& b, std::size_t offset, std::size_t size)
        : m_offset(offset), m_size(size), m_bulk(b) {}

Matthieu Dorier's avatar
Matthieu Dorier committed
84 85 86
        /**
         * @brief Copy constructor is deleted.
         */
Matthieu Dorier's avatar
Matthieu Dorier committed
87
        bulk_segment(const bulk_segment&) = default;
Matthieu Dorier's avatar
Matthieu Dorier committed
88 89 90 91

        /**
         * @brief Move constructor is default.
         */
Matthieu Dorier's avatar
Matthieu Dorier committed
92 93
        bulk_segment(bulk_segment&&)      = default;

Matthieu Dorier's avatar
Matthieu Dorier committed
94 95 96
        /**
         * @brief Destructor is default.
         */
Matthieu Dorier's avatar
Matthieu Dorier committed
97 98
        ~bulk_segment()                   = default;

Matthieu Dorier's avatar
Matthieu Dorier committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        /**
         * @brief Associates the bulk segment with an endpoint to represent
         * a remote_bulk object.
         *
         * @param ep Endpoint where the bulk object has bee created.
         *
         * @return a remote_bulk object.
         */
        remote_bulk on(const endpoint& ep) const;

        /**
         * @brief Pushes data from the left operand (bulk_segment)
         * to the right operand (remote_bulk). If the size of the
         * segments don't match, the smallest size is used.
         *
         * @param b remote_bulk object towards which to push data.
         *
         * @return the size of data transfered.
         */
        std::size_t operator>>(const remote_bulk& b) const;

        /**
         * @brief Pulls data from the right operand (remote_bulk)
         * to the right operand (bulk_segment). If the size of the
         * segments don't match, the smallest size is used.
         *
         * @param b remote_bulk object from which to pull data.
         *
         * @return the size of data transfered.
         */
        std::size_t operator<<(const remote_bulk& b) const;
Matthieu Dorier's avatar
Matthieu Dorier committed
130 131 132 133
    };

public:

Matthieu Dorier's avatar
Matthieu Dorier committed
134 135 136 137
    /**
     * @brief Default constructor, defined so that one can have a bulk
     * object as class member and associate it later with an actual bulk.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
138
    bulk()
Matthieu Dorier's avatar
Matthieu Dorier committed
139
    : m_engine(nullptr), m_bulk(HG_BULK_NULL), m_is_local(false), m_eager_mode(false) {}
Matthieu Dorier's avatar
Matthieu Dorier committed
140

Matthieu Dorier's avatar
Matthieu Dorier committed
141 142 143
    /**
     * @brief Copy constructor.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
144
	bulk(const bulk& other)
Matthieu Dorier's avatar
Matthieu Dorier committed
145 146
    : m_engine(other.m_engine), m_bulk(other.m_bulk), 
      m_is_local(other.m_is_local), m_eager_mode(other.m_eager_mode) {
147 148
        hg_return_t ret = margo_bulk_ref_incr(m_bulk);
        MARGO_ASSERT(ret, margo_bulk_ref_incr);
Matthieu Dorier's avatar
Matthieu Dorier committed
149 150
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
151 152 153
    /**
     * @brief Move constructor.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
154
	bulk(bulk&& other)
Matthieu Dorier's avatar
Matthieu Dorier committed
155 156 157
	: m_engine(other.m_engine), m_bulk(other.m_bulk),
      m_is_local(other.m_is_local), 
      m_eager_mode(other.m_eager_mode) {
Matthieu Dorier's avatar
Matthieu Dorier committed
158 159 160
		other.m_bulk     = HG_BULK_NULL;
	}

Matthieu Dorier's avatar
Matthieu Dorier committed
161 162 163
    /**
     * @brief Copy-assignment operator.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
164 165 166
	bulk& operator=(const bulk& other) {
        if(this == &other) return *this;
        if(m_bulk != HG_BULK_NULL) {
167 168
            hg_return_t ret = margo_bulk_free(m_bulk);
            MARGO_ASSERT(ret, margo_bulk_free);
Matthieu Dorier's avatar
Matthieu Dorier committed
169 170 171 172
        }
        m_bulk     = other.m_bulk;
        m_engine   = other.m_engine;
        m_is_local = other.m_is_local;
Matthieu Dorier's avatar
Matthieu Dorier committed
173
        m_eager_mode = other.m_eager_mode;
Matthieu Dorier's avatar
Matthieu Dorier committed
174
        if(m_bulk != HG_BULK_NULL) {
175 176
            hg_return_t ret = margo_bulk_ref_incr(m_bulk);
            MARGO_ASSERT(ret, margo_bulk_ref_incr);
Matthieu Dorier's avatar
Matthieu Dorier committed
177 178 179 180
        }
        return *this;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
181 182 183
    /**
     * @brief Move-assignment operator.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
184 185 186
	bulk& operator=(bulk&& other) {
        if(this == &other) return *this;
        if(m_bulk != HG_BULK_NULL) {
187 188
            hg_return_t ret = margo_bulk_free(m_bulk);
            MARGO_ASSERT(ret, margo_bulk_free);
Matthieu Dorier's avatar
Matthieu Dorier committed
189 190 191 192
        }
        m_engine     = other.m_engine;
        m_bulk       = other.m_bulk;
        m_is_local   = other.m_is_local;
Matthieu Dorier's avatar
Matthieu Dorier committed
193
        m_eager_mode = other.m_eager_mode;
Matthieu Dorier's avatar
Matthieu Dorier committed
194 195 196 197
        other.m_bulk = HG_BULK_NULL;
        return *this;
    }
	
Matthieu Dorier's avatar
Matthieu Dorier committed
198 199 200
    /**
     * @brief Destructor.
     */
Rob Latham's avatar
Rob Latham committed
201
	~bulk() {
Matthieu Dorier's avatar
Matthieu Dorier committed
202
        if(m_bulk != HG_BULK_NULL) {
203 204
            hg_return_t ret = margo_bulk_free(m_bulk);
            MARGO_ASSERT(ret, margo_bulk_free);
Matthieu Dorier's avatar
Matthieu Dorier committed
205 206 207
        }
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
208 209 210 211 212
    /**
     * @brief Returns the size of the data exposed by the bulk object.
     *
     * @return size of data exposed by the bulk object.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
213 214 215 216 217 218 219
    std::size_t size() const {
        if(m_bulk != HG_BULK_NULL)
            return margo_bulk_get_size(m_bulk);
        else
            return 0;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
220 221 222 223 224
    /**
     * @brief Indicates whether the bulk handle is null.
     *
     * @return true if the bulk handle is null, false otherwise.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
225 226 227 228
    bool is_null() const {
        return m_bulk == HG_BULK_NULL;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
229 230 231 232 233 234 235 236 237 238 239
    /**
     * @brief Set the eager mode. When eager mode is true,
     * Mercury will try to send the bulk's exposed data along
     * with the bulk handle when sending the bulk handle over RPC.
     *
     * @param eager Whether to use eager mode or not.
     */
    void set_eager_mode(bool eager) {
        m_eager_mode = eager;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
    /**
     * @brief Builds a remote_bulk object by associating it with an endpoint.
     *
     * @param ep endpoint with which the bulk object should be associated.
     *
     * @return a remote_bulk instance.
     */
    remote_bulk on(const endpoint& ep) const;

    /**
     * @brief Creates a bulk_segment object by selecting a given portion
     * of the bulk object given an offset and a size.
     *
     * @param offset Offset at which the segment starts.
     * @param size Size of the segment.
     *
     * @return a bulk_segment object.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
258 259 260
    bulk_segment select(std::size_t offset, std::size_t size) const;


Matthieu Dorier's avatar
Matthieu Dorier committed
261 262 263 264
    /**
     * @see bulk::select
     */
    bulk_segment operator()(std::size_t offset, std::size_t size) const;
265

Matthieu Dorier's avatar
Matthieu Dorier committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
    /**
     * @brief Pushes data from the left operand (entire bulk object)
     * to the right operand (remote_bulk). If the size of the
     * segments don't match, the smallest size is used.
     *
     * @param b remote_bulk object towards which to push data.
     *
     * @return the size of data transfered.
     */
    std::size_t operator>>(const remote_bulk& b) const;

    /**
     * @brief Pulls data from the right operand (remote_bulk)
     * to the left operand (bulk). If the size of the
     * segments don't match, the smallest size is used.
     *
     * @param b remote_bulk object from which to pull data.
     *
     * @return the size of data transfered.
     */
    std::size_t operator<<(const remote_bulk& b) const;

    /**
     * @brief Function that serializes a bulk object into an archive.
     *
     * @tparam A Archive type.
     * @param ar Input archive.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
294 295
    template<typename A>
    void save(A& ar) {
Matthieu Dorier's avatar
Matthieu Dorier committed
296 297 298 299
        if(m_bulk == HG_BULK_NULL) {
            std::vector<char> buf;
            ar & buf;
        } else {
Matthieu Dorier's avatar
Matthieu Dorier committed
300 301
            auto use_eager = m_eager_mode ? HG_TRUE : HG_FALSE;
            hg_size_t s = margo_bulk_get_serialize_size(m_bulk, use_eager);
Matthieu Dorier's avatar
Matthieu Dorier committed
302
            std::vector<char> buf(s);
Matthieu Dorier's avatar
Matthieu Dorier committed
303
            hg_return_t ret = margo_bulk_serialize(&buf[0], s, use_eager, m_bulk);
304
            MARGO_ASSERT(ret, margo_bulk_serialize);
Matthieu Dorier's avatar
Matthieu Dorier committed
305 306
            ar & buf;
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
307 308
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
309 310 311 312 313 314
    /**
     * @brief Deserializes a bulk object from an output archive.
     *
     * @tparam A Archive type.
     * @param ar Output archive.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
315 316 317 318 319 320 321 322 323 324 325 326 327
    template<typename A>
    void load(A& ar);

};

}

#include <thallium/engine.hpp>

namespace thallium {

template<typename A>
void bulk::load(A& ar) {
Matthieu Dorier's avatar
Matthieu Dorier committed
328 329 330
    if(!is_null()) {
        *this = bulk(); // reset
    }
Matthieu Dorier's avatar
Matthieu Dorier committed
331 332
    std::vector<char> buf;
    ar & buf;
Matthieu Dorier's avatar
Matthieu Dorier committed
333 334
    if(buf.size() > 0) {
        m_engine = &(ar.get_engine());
335 336
        hg_return_t ret = margo_bulk_deserialize(m_engine->m_mid, &m_bulk, &buf[0], buf.size());
        MARGO_ASSERT(ret, margo_bulk_deserialize);
Matthieu Dorier's avatar
Matthieu Dorier committed
337 338
        m_is_local = false;
    }
Matthieu Dorier's avatar
Matthieu Dorier committed
339 340 341 342 343
}

}

#endif