1.. Copyright (C) 2004-2008 The Trustees of Indiana University. 2 Use, modification and distribution is subject to the Boost Software 3 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 http://www.boost.org/LICENSE_1_0.txt) 5 6================================== 7|Logo| Parallel BGL Process Groups 8================================== 9 10.. contents:: 11 12Introduction 13------------ 14 15Process groups are an abstraction of a set of communicating processes 16that coordinate to solve the same problem. Process groups contain 17facilities for identifying the processes within that group, sending 18and receiving messages between the processes in that group, and 19performing collective communications involving all processes in the 20group simultaneously. 21 22Communication model 23------------------- 24 25Process groups are based on an extended version of the Bulk 26Synchronous Parallel (BSP) model of computation. Parallel computations 27in the BSP model are organized into *supersteps*, each of which 28consists of a computation phase followed by a communication 29phase. During the computation phase, all processes in the process 30group work exclusively on local data, and there is no inter-process 31communication. During the communication phase, all of the processes 32exchange message with each other. Messages sent in the communication 33phase of a superstep will be received in the next superstep. 34 35The boundary between supersteps in the Parallel BGL corresponds to the 36``synchronize`` operation. Whenever a process has completed its local 37computation phase and sent all of the messages required for that 38superstep, it invokes the ``synchronize`` operation on the process 39group. Once all processes in the process group have entered 40``synchronize``, they exchange messages and then continue with the 41next superstep. 42 43The Parallel BGL loosens the BSP model significantly, to provide a 44more natural programming model that also provides some performance 45benefits over the strict BSP model. The primary extension is the 46ability to receive messages sent within the same superstep 47"asynchronously", either to free up message buffers or to respond to 48an immediate request for information. For particularly unstructured 49computations, the ability to send a message and get an immediate reply 50can simplify many computations that would otherwise need to be split 51into two separate supersteps. Additionally, the Parallel BGL augments 52the BSP model with support for multiple distributed data structures, 53each of which are provided with a different communication space but 54whose messages will all be synchronized concurrently. 55 56Distributed data structures 57~~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 59A typical computation with the Parallel BGL involves several 60distributed data structures working in concern. For example, a simple 61breadth-first search involves the distributed graph data structure 62containing the graph itself, a distributed queue that manages the 63traversal through the graph, and a distributed property map that 64tracks which vertices have already been visited as part of the 65search. 66 67The Parallel BGL manages these distributed data structures by allowing 68each of the data structures to attach themselves to the process group 69itself. When a distributed data structure attaches to the process 70group, it receives its own copy of the process group that allows the 71distributed data structure to communicate without colliding with the 72communications from other distributed data structures. When the 73process group is synchronized, all of the distributed data structures 74attached to that process group are automatically synchronized, so that 75all of the distributed data structures in a computation remain 76synchronized. 77 78A distributed data structure attaches itself to the process group by 79creating a copy of the process group and passing an 80``attach_distributed_object`` flag to the process group 81constructor. So long as this copy of the process group persists, the 82distributed data structure is attached the process group. For this 83reason, most distributed data structures keep a copy of the process 84group as member data, constructing the member with 85``attach_distributed_object``, e.g., 86 87:: 88 89 template<typename ProcessGroup> 90 struct distributed_data_structure 91 { 92 explicit distributed_data_structure(const ProcessGroup& pg) 93 : process_group(pg, boost::parallel::attach_distributed_object()) 94 { } 95 96 private: 97 ProcessGroup process_group; 98 }; 99 100 101Asynchronous receives 102~~~~~~~~~~~~~~~~~~~~~ 103 104Distributed data structures in the Parallel BGL can "asynchronously" 105receive and process messages before the end of a BSP 106superstep. Messages can be received any time that a process is inside 107the process group operations, and the scheduling of message receives 108is entirely managed by the process group. 109 110Distributed data structures receive messages through 111"triggers". Triggers are function objects responsible for processing a 112received message. Each trigger is registered with the ``trigger`` 113method of the process group using a specific message 114tag (an integer) and the type of data that is expected to be 115contained within that message. Whenever a message with that tag 116becomes available, the progress group will call the trigger with the 117source of the message, the message tag, the data contained in the 118message, and the "context" of the message. 119 120The majority of triggers have no return value, although it is common 121that the triggers send messages back to the source process. In certain 122cases where the trigger's purpose is to immediately reply with a 123value, the trigger should be registered with the 124``trigger_with_reply`` method and should return the value that will be 125sent back to the caller. The ``trigger_with_reply`` facility is only 126useful in conjunction with out-of-band messaging, discussed next. 127 128Out-of-band messaging 129~~~~~~~~~~~~~~~~~~~~~ 130 131The majority of messages sent by the Parallel BGL are sent through the 132normal send operations, to be received in the next superstep or, in 133some cases, received "early" by a trigger. These messages are not 134time-sensitive, so they will be delivered whenever the process group 135processes them. 136 137Some messages, however, require immediate responses. For example, if a 138process needs to determine the current value associated with a vertex 139owned by another process, the first process must send a request to the 140second process and block while waiting for a response. For such 141messages, the Parallel BGL's process groups provide an out-of-band 142messaging mechanism. Out-of-band messages are transmitted immediately, 143with a much higher priority than other messages. The sending of 144out-of-band messages can be coupled with a receive operation that 145waits until the remote process has received the message and sent its 146reply. For example, in the following code the process sends a message 147containing the string ``name`` to process ``owner`` with tag 148``msg_get_descriptor_by_name`` via an out-of-band message. The 149receiver of that message will immediately deliver the message via a 150trigger, that returns the resulting value--a 151``vertex_descriptor``--that will be passed back to the process that 152initiated the communication. The full communication happens 153immediately, within the current superstep. 154 155:: 156 157 std::string name; 158 vertex_descriptor descriptor; 159 send_oob_with_reply(process_group, owner, msg_get_descriptor_by_name, 160 name, descriptor); 161 162Reference 163--------- 164 165The Parallel BGL process groups specify an interface that can be 166implemented by various communication subsystems. In this reference 167section, we use the placeholder type ``ProcessGroup`` to stand in for 168the various process group implementations that exist. There is only 169one implementation of the process group interface at this time: 170 171 - `MPI BSP process group`_ 172 173:: 174 175 enum trigger_receive_context { 176 trc_none, 177 trc_in_synchronization, 178 trc_early_receive, 179 trc_out_of_band 180 }; 181 182 class ProcessGroup 183 { 184 // Process group constructors 185 ProcessGroup(); 186 ProcessGroup(const ProcessGroup&, boost::parallel::attach_distributed_object); 187 188 // Triggers 189 template<typename Type, typename Handler> 190 void trigger(int tag, const Handler& handler); 191 192 template<typename Type, typename Handler> 193 void trigger_with_reply(int tag, const Handler& handler); 194 195 trigger_receive_context trigger_context() const; 196 197 // Helper operations 198 void poll(); 199 ProcessGroup base() const; 200 }; 201 202 // Process query 203 int process_id(const ProcessGroup&); 204 int num_processes(const ProcessGroup&); 205 206 // Message transmission 207 template<typename T> 208 void send(const ProcessGroup& pg, int dest, int tag, const T& value); 209 210 template<typename T> 211 void receive(const ProcessGroup& pg, int source, int tag, T& value); 212 213 optional<std::pair<int, int> > probe(const ProcessGroup& pg); 214 215 // Synchronization 216 void synchronize(const ProcessGroup& pg); 217 218 // Out-of-band communication 219 template<typename T> 220 void send_oob(const ProcessGroup& pg, int dest, int tag, const T& value); 221 222 template<typename T, typename U> 223 void 224 send_oob_with_reply(const ProcessGroup& pg, int dest, int 225 tag, const T& send_value, U& receive_value); 226 227 template<typename T> 228 void receive_oob(const ProcessGroup& pg, int source, int tag, T& value); 229 230 231Process group constructors 232~~~~~~~~~~~~~~~~~~~~~~~~~~ 233 234:: 235 236 ProcessGroup(); 237 238Constructs a new process group with a different communication space 239from any other process group. 240 241----------------------------------------------------------------------------- 242 243:: 244 245 ProcessGroup(const ProcessGroup& pg, boost::parallel::attach_distributed_object); 246 247Attaches a new distributed data structure to the process group 248``pg``. The resulting process group can be used for communication 249within that new distributed data structure. When the newly-constructed 250process group is eventually destroyed, the distributed data structure 251is detached from the process group. 252 253Triggers 254~~~~~~~~ 255 256:: 257 258 template<typename Type, typename Handler> 259 void trigger(int tag, const Handler& handler); 260 261Registers a trigger with the given process group. The trigger will 262watch for messages with the given ``tag``. When such a message is 263available, it will be received into a value of type ``Type``, and the 264function object ``handler`` will be invoked with four parameters: 265 266source 267 The rank of the source process (an ``int``) 268 269tag 270 The tag used to send the message (also an ``int``) 271 272data: 273 The data transmitted with the message. The data will have the type 274 specified when the trigger was registered. 275 276context: 277 The context in which the trigger is executed. This will be a value of 278 type ``trigger_receive_context``, which stages whether the trigger 279 is being executed during synchronization, asynchronously in response 280 to an "early" receive (often to free up communication buffers), or 281 in response to an "out-of-band" message. 282 283Triggers can only be registered by process groups that result from 284attaching a distributed data structure. A trigger can be invoked in 285response to either a normal send operation or an out-of-band send 286operation. There is also a `simple trigger interface`_ for defining 287triggers in common cases. 288 289----------------------------------------------------------------------------- 290 291:: 292 293 template<typename Type, typename Handler> 294 void trigger_with_reply(int tag, const Handler& handler); 295 296Like the ``trigger`` method, registers a trigger with the given 297process group. The trigger will watch for messages with the given 298``tag``. When such a message is available, it will be received into a 299value of type ``Type`` and ``handler`` will be invoked, just as with a 300normal trigger. However, a trigger registered with 301``trigger_with_reply`` must return a value, which will be immediately 302sent back to the process that initiated the send resulting in this 303trigger. Thus, ``trigger_with_reply`` should only be used for messages 304that need immediate responses. These triggers can only be invoked via 305the out-of-band sends that wait for the reply, via 306``send_oob_with_reply``. There is also a `simple trigger interface`_ 307for defining triggers in common cases. 308 309----------------------------------------------------------------------------- 310 311:: 312 313 trigger_receive_context trigger_context() const; 314 315Retrieves the current context of the process group with respect to the 316invocation of triggers. When ``trc_none``, the process group is not 317currently invoking any triggers. Otherwise, this value describes in 318what context the currently executing trigger is being invoked. 319 320 321Helper operations 322~~~~~~~~~~~~~~~~~ 323 324:: 325 326 void poll(); 327 328Permits the process group to receive any incomining messages, 329processing them via triggers. If you have a long-running computation 330that does not invoke any of the process group's communication 331routines, you should call ``poll`` occasionally to along incoming 332messages to be processed. 333 334----------------------------------------------------------------------------- 335 336:: 337 338 ProcessGroup base() const; 339 340Retrieves the "base" process group for this process group, which is a 341copy of the underlying process group that does not reference any 342specific distributed data structure. 343 344Process query 345~~~~~~~~~~~~~ 346 347:: 348 349 int process_id(const ProcessGroup& pg); 350 351Retrieves the ID (or "rank") of the calling process within the process 352group. Process IDs are values in the range [0, ``num_processes(pg)``) 353that uniquely identify the process. Process IDs can be used to 354initiate communication with another process. 355 356----------------------------------------------------------------------------- 357 358:: 359 360 int num_processes(const ProcessGroup& pg); 361 362Returns the number of processes within the process group. 363 364 365Message transmission 366~~~~~~~~~~~~~~~~~~~~ 367 368:: 369 370 template<typename T> 371 void send(const ProcessGroup& pg, int dest, int tag, const T& value); 372 373Sends a message with the given ``tag`` and carrying the given 374``value`` to the process with ID ``dest`` in the given process 375group. All message sends are non-blocking, meaning that this send 376operation will not block while waiting for the communication to 377complete. There is no guarantee when the message will be received, 378except that it will become available to the destination process by the 379end of the superstep, in the collective call to ``synchronize``. 380 381Any type of value can be transmitted via ``send``, so long as it 382provides the appropriate functionality to be serialized with the 383Boost.Serialization library. 384 385----------------------------------------------------------------------------- 386 387:: 388 389 template<typename T> 390 void receive(const ProcessGroup& pg, int source, int tag, T& value); 391 392Receives a message with the given ``tag`` sent from the process 393``source``, updating ``value`` with the payload of the message. This 394receive operation can only receive messages sent within the previous 395superstep via the ``send`` operation. If no such message is available 396at the time ``receive`` is called, the program is ill-formed. 397 398----------------------------------------------------------------------------- 399 400:: 401 402 optional<std::pair<int, int> > probe(const ProcessGroup& pg); 403 404Determines whether a message is available. The probe operation checks 405for any messages that were sent in the previous superstep but have not 406yet been received. If such a message exists, ``probe`` returns a 407(source, tag) pair describing the message. Otherwise, ``probe`` will 408return an empty ``boost::optional``. 409 410A typical use of ``probe`` is to continually probe for messages at the 411beginning of the superstep, receiving and processing those messages 412until no messages remain. 413 414 415Synchronization 416~~~~~~~~~~~~~~~ 417 418:: 419 420 void synchronize(const ProcessGroup& pg); 421 422The ``synchronize`` function is a collective operation that must be 423invoked by all of the processes within the process group. A call to 424``synchronize`` marks the end of a superstep in the parallel 425computation. All messages sent before the end of the superstep will be 426received into message buffers, and can be processed by the program in 427the next superstep. None of the processes will leave the 428``synchronize`` function until all of the processes have entered the 429function and exchanged messages, so that all processes are always on 430the same superstep. 431 432Out-of-band communication 433~~~~~~~~~~~~~~~~~~~~~~~~~ 434 435:: 436 437 template<typename T> 438 void send_oob(const ProcessGroup& pg, int dest, int tag, const T& value); 439 440Sends and out-of-band message. This out-of-band send operation acts 441like the normal ``send`` operation, except that out-of-band messages 442are delivered immediately through a high-priority channel. 443 444----------------------------------------------------------------------------- 445 446:: 447 448 template<typename T, typename U> 449 void 450 send_oob_with_reply(const ProcessGroup& pg, int dest, int 451 tag, const T& send_value, U& receive_value); 452 453Sends an out-of-band message and waits for a reply. The 454``send_oob_with_reply`` function can only be invoked with message tags 455that correspond to triggers registered with 456``trigger_with_reply``. This operation will send the message 457immediately (through the high-priority, out-of-band channel), then 458wait until the remote process sends a reply. The data from the reply 459is stored into ``receive_value``. 460 461----------------------------------------------------------------------------- 462 463:: 464 465 template<typename T> 466 void receive_oob(const ProcessGroup& pg, int source, int tag, T& value); 467 468Receives an out-of-band message with the given ``source`` and 469``tag``. As with the normal ``receive`` operation, it is an error to 470call ``receive_oob`` if no message matching the source and tag is 471available. This routine is used only rarely; for most circumstances, 472use ``send_oob_with_reply`` to perform an immediate send with a 473reply. 474 475----------------------------------------------------------------------------- 476 477Copyright (C) 2007 Douglas Gregor 478 479Copyright (C) 2007 Matthias Troyer 480 481.. |Logo| image:: pbgl-logo.png 482 :align: middle 483 :alt: Parallel BGL 484 :target: http://www.osl.iu.edu/research/pbgl 485 486.. _MPI BSP process group: mpi_bsp_process_group.html 487.. _Simple trigger interface: simple_trigger.html 488