FreeNOS
MpiHost.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <errno.h>
22#include <libgen.h>
23#include <sys/stat.h>
24#include <sys/socket.h>
25#include <Log.h>
26#include <List.h>
27#include <ListIterator.h>
28#include <String.h>
29#include <MpiProxy.h>
30#include "MpiHost.h"
31
33{
34 return new MpiHost();
35}
36
40
42 char ***argv)
43{
44 // Verify input arguments
45 if ((*argc) < 2)
46 {
47 ERROR("invalid number of arguments given");
48 return MPI_ERR_ARG;
49 }
50
51 // Add ourselves as the master node
52 Node *master = new Node;
53 master->ipAddress = 0;
54 master->udpPort = 0;
55 master->coreId = 0;
56
57 // Register the master
58 if (!m_nodes.insert(master))
59 {
60 ERROR("failed to add master Node object");
61 return MPI_ERR_IO;
62 }
63
64 // Read list of hosts from the given file
65 const Result hostsResult = parseHostsFile((*argv)[1]);
66 if (hostsResult != MPI_SUCCESS)
67 {
68 ERROR("failed to parse hosts file at path " << (*argv)[1] <<
69 ": result = " << (int) hostsResult);
70 return hostsResult;
71 }
72
73 // Pass the rest of the arguments to the user program
74 (*argc) -= 1;
75 (*argv)[1] = (*argv)[0];
76 (*argv) += 1;
77
78 // Create UDP socket
79 m_sock = socket(AF_INET, SOCK_DGRAM, 0);
80 if (m_sock < 0)
81 {
82 ERROR("failed to create UDP socket: " << strerror(errno));
83 return MPI_ERR_IO;
84 }
85
86 // Prepare local address and port to bind to
87 struct sockaddr_in addr;
88 memset((char *)&addr, 0, sizeof(addr));
89 addr.sin_family = AF_INET;
90 addr.sin_addr.s_addr = htonl(INADDR_ANY);
91 addr.sin_port = htons(0);
92
93 // Bind the UDP socket
94 int bindResult = bind(m_sock, (struct sockaddr *) &addr, sizeof(addr));
95 if (bindResult < 0)
96 {
97 ERROR("failed to bind UDP socket: " << strerror(errno));
98 return MPI_ERR_IO;
99 }
100
101 // Launch remote programs
102 return startProcesses(*argc, *argv);
103}
104
106{
107 // Loop all nodes
108 for (Size i = 1; i < m_nodes.count(); i++)
109 {
110 static u8 packet[MpiProxy::MaximumPacketSize];
111 Size packetSize = sizeof(MpiProxy::Header);
112
113 // Send terminate request to the remote node
114 MpiProxy::Header *hdr = (MpiProxy::Header *) packet;
116 hdr->coreId = m_nodes[i]->coreId;
117 hdr->rankId = i;
118
119 // Send the packet
120 const Result sendResult = sendPacket(i, packet, sizeof(MpiProxy::Header));
121 if (sendResult != MPI_SUCCESS)
122 {
123 ERROR("failed to send packet to nodeId " << i << ": result = " << (int) sendResult);
124 return sendResult;
125 }
126
127 // Wait for reply
128 const Result recvResult = receivePacket(i, MpiProxy::MpiOpTerminate, packet, packetSize);
129 if (recvResult != MPI_SUCCESS)
130 {
131 ERROR("failed to receive UDP packet for rankId = " << i << ": result = " << (int) recvResult);
132 return recvResult;
133 }
134
135 // The packet must be a terminate response
136 const MpiProxy::Header *header = (const MpiProxy::Header *) packet;
137 if (header->operation != MpiProxy::MpiOpTerminate)
138 {
139 ERROR("invalid response received: op = " << header->operation);
140 continue;
141 }
142
143 // Verify the result code
144 if (header->result != MPI_SUCCESS)
145 {
146 ERROR("rankId " << i << " failed to terminate with result = " << header->result);
147 continue;
148 }
149
150 NOTICE("rankId " << i << " terminated");
151 }
152
153 return MPI_SUCCESS;
154}
155
157 int *rank)
158{
159 *rank = 0;
160 return MPI_SUCCESS;
161}
162
164 int *size)
165{
166 *size = m_nodes.count();
167 return MPI_SUCCESS;
168}
169
171 int count,
172 MPI_Datatype datatype,
173 int dest,
174 int tag,
175 MPI_Comm comm)
176{
177 Size datasize = 0;
178
179 // Get datatype size
180 switch (datatype)
181 {
182 case MPI_INT:
183 datasize = sizeof(int);
184 break;
185
187 datasize = sizeof(u8);
188 break;
189
190 default: {
191 ERROR("unsupported datatype = " << (int) datatype);
192 return MPI_ERR_ARG;
193 }
194 }
195
196 // Large payloads are not yet supported
197 if ((count * datasize) + sizeof(MpiProxy::Header) > MpiProxy::MaximumPacketSize)
198 {
199 ERROR("data count too high: maximum is " <<
201 return MPI_ERR_ARG;
202 }
203
204 // Find the destination node
205 const Node *node = m_nodes.get(dest);
206 if (node == ZERO)
207 {
208 ERROR("nodeId " << dest << " not found");
209 return MPI_ERR_ARG;
210 }
211
212 // Construct packet to send
214 MpiProxy::Header *hdr = (MpiProxy::Header *) packet;
216 hdr->result = 0;
217 hdr->coreId = node->coreId;
218 hdr->rankId = dest;
219 hdr->datatype = datatype;
220 hdr->datacount = count;
221
222 // Append payload after the header
223 MemoryBlock::copy(packet + sizeof(MpiProxy::Header), buf, count * datasize);
224
225 // Send the packet
226 const Result sendResult = sendPacket(dest, packet, sizeof(MpiProxy::Header) + (count * datasize));
227 if (sendResult != MPI_SUCCESS)
228 {
229 ERROR("failed to send packet to nodeId " << dest << ": result = " << (int) sendResult);
230 return sendResult;
231 }
232
233 return MPI_SUCCESS;
234}
235
237 int count,
238 MPI_Datatype datatype,
239 int source,
240 int tag,
241 MPI_Comm comm,
242 MPI_Status *status)
243{
244 static u8 packet[MpiProxy::MaximumPacketSize];
245
246 // Find the source node
247 const Node *node = m_nodes.get(source);
248 if (node == ZERO)
249 {
250 ERROR("nodeId " << source << " not found");
251 return MPI_ERR_RANK;
252 }
253
254 // Send receive data request to the remote node
255 MpiProxy::Header *hdr = (MpiProxy::Header *) packet;
257 hdr->coreId = node->coreId;
258 hdr->rankId = source;
259 hdr->datatype = datatype;
260 hdr->datacount = count;
261
262 // Send the packet
263 const Result sendResult = sendPacket(source, packet, sizeof(MpiProxy::Header));
264 if (sendResult != MPI_SUCCESS)
265 {
266 ERROR("failed to send packet to nodeId " << source << ": result = " << (int) sendResult);
267 return sendResult;
268 }
269
270 // Now receive the data response(s)
271 for (int i = 0; i < count;)
272 {
273 Size packetSize = sizeof(packet);
274
275 // Receive data packet from the source node
276 const Result recvResult = receivePacket(source, MpiProxy::MpiOpRecv, packet, packetSize);
277 if (recvResult != MPI_SUCCESS)
278 {
279 ERROR("failed to receive UDP packet for rankId = " << source << ": result = " << (int) recvResult);
280 return recvResult;
281 }
282
283 // The packet must be a data response
284 const MpiProxy::Header *header = (const MpiProxy::Header *) packet;
285 if (header->operation != MpiProxy::MpiOpRecv)
286 {
287 ERROR("invalid response received: op = " << header->operation);
288 continue;
289 }
290
291 // Process all the received data
292 for (Size j = 0; j < header->datacount; j++, i++)
293 {
294 const u8 *data = ((const u8 *)(header + 1)) + j;
295
296 switch (datatype)
297 {
298 case MPI_INT:
299 *(((int *) buf) + i) = *(int *)(data);
300 break;
301
303 *(((u8 *) buf) + i) = *data;
304 break;
305
306 default:
308 }
309 }
310 }
311
312 return MPI_SUCCESS;
313}
314
316{
317 struct stat st;
318 FILE *fp;
319
320 DEBUG("hostsfile = " << hostsfile);
321
322 if (stat(hostsfile, &st) != 0)
323 {
324 ERROR("failed to stat() `" << hostsfile << "': " << strerror(errno));
325 return MPI_ERR_IO;
326 }
327
328 // Open file
329 if ((fp = fopen(hostsfile, "r")) == NULL)
330 {
331 ERROR("failed to fopen() `" << hostsfile << "': " << strerror(errno));
332 return MPI_ERR_IO;
333 }
334
335 // Allocate buffer storage
336 char *contents = new char[st.st_size + 1];
337 if (!contents)
338 {
339 ERROR("failed to allocate memory buffer for hostsfile: " << strerror(errno));
340 return MPI_ERR_NO_MEM;
341 }
342
343 // Read the entire file into memory
344 if (fread(contents, st.st_size, 1, fp) != (size_t) 1U)
345 {
346 ERROR("failed to fread() `" << hostsfile << "': " << strerror(errno));
347 fclose(fp);
348 return MPI_ERR_IO;
349 }
350 fclose(fp);
351
352 // Null terminate
353 contents[st.st_size] = 0;
354
355 // Parse it into lines
356 String contentString(contents);
357 List<String> lines = contentString.split('\n');
358
359 // Add each line as IP address of Execute each command
360 for (ListIterator<String> i(lines); i.hasCurrent(); i++)
361 {
362 // Skip comment lines
363 if (i.current()[0] == '#')
364 {
365 continue;
366 }
367
368 List<String> nodeLine = i.current().split(':');
369 Size idx;
370
371 // Nodes must be listed in the format: <ip>:<port>:<core>
372 if (nodeLine.count() != 3)
373 {
374 ERROR("invalid host format '" << *i.current() << "' in hosts file at " << hostsfile);
375 delete[] contents;
376 return MPI_ERR_ARG;
377 }
378
379 Node *node = new Node();
380 if (!node)
381 {
382 ERROR("failed to allocate Node object: " << strerror(errno));
383 delete[] contents;
384 return MPI_ERR_NO_MEM;
385 }
386
387 // Add the node
388 node->ipAddress = inet_addr(*nodeLine[0]);
389 node->udpPort = atoi(*nodeLine[1]);
390 node->coreId = atoi(*nodeLine[2]);
391
392 if (!m_nodes.insert(idx, node))
393 {
394 ERROR("failed to insert Node object");
395 delete[] contents;
396 return MPI_ERR_IO;
397 }
398
399 // Add packet buffer list
400 List<Packet *> *lst = new List<Packet *>();
401 if (!lst)
402 {
403 ERROR("failed to allocate List<..> object: " << strerror(errno));
404 delete[] contents;
405 return MPI_ERR_NO_MEM;
406 }
407 m_packetBuffers.insertAt(idx, lst);
408
409 DEBUG("m_nodes[" << idx << "]: ip = " << *nodeLine[0] << ", port = " << *nodeLine[1] <<
410 ", core = " << *nodeLine[2]);
411 }
412
413 // Cleanup
414 delete[] contents;
415 return MPI_SUCCESS;
416}
417
419 char **argv)
420{
421 const Size NumOfParallelStart = 32;
422 static u8 packet[MpiProxy::MaximumPacketSize];
423 MpiProxy::Header *hdr = (MpiProxy::Header *) packet;
424 String cmdline;
425 Size startIndex = 1, startCount = 0;
426
427 DEBUG("argc = " << argc);
428
429 // First add the program name
430 cmdline << basename(argv[0]);
431 if (argc > 1)
432 {
433 cmdline << " ";
434 }
435
436 // Append any extra arguments
437 for (int i = 1; i < argc; i++)
438 {
439 cmdline << argv[i];
440
441 if (i != argc - 1)
442 {
443 cmdline << " ";
444 }
445 }
446
447 // Start remote processes with the constructed command line
448 NOTICE("cmdline = " << *cmdline);
449
450 // Send out packets to all the hosts
451 while (startIndex < m_nodes.count())
452 {
453 const Size receiveIndex = startIndex;
454
455 // Limit the number of parallel requests
456 while (startIndex < m_nodes.count() && startCount < NumOfParallelStart)
457 {
458 in_addr nodeAddr;
459 nodeAddr.s_addr = m_nodes[startIndex]->ipAddress;
460
461 NOTICE("nodes[" << startIndex << "] = " << inet_ntoa(nodeAddr) <<
462 ":" << m_nodes[startIndex]->udpPort << ":" << m_nodes[startIndex]->coreId);
463
464 // Construct packet to send
466 hdr->result = 0;
467 hdr->rankId = startIndex;
468 hdr->coreId = m_nodes[startIndex]->coreId;
469 hdr->coreCount = m_nodes.count();
470
471 // Append command-line after the header
472 MemoryBlock::copy((char *)packet + sizeof(MpiProxy::Header), *cmdline,
473 sizeof(packet) - sizeof(MpiProxy::Header));
474
475 // Send the packet
476 const Result sendResult = sendPacket(startIndex, packet, sizeof(MpiProxy::Header) + cmdline.length());
477 if (sendResult != MPI_SUCCESS)
478 {
479 ERROR("failed to send packet to nodeId " << startIndex << ": result = " << (int) sendResult);
480 return sendResult;
481 }
482 startIndex++;
483 startCount++;
484 }
485
486 // Wait for acknowledge of each node
487 for (Size i = receiveIndex; i < startIndex; i++)
488 {
489 Size sz;
490 sz = sizeof(MpiProxy::Header);
491
492 const Result recvResult = receivePacket(i, MpiProxy::MpiOpExec, &packet, sz);
493 if (recvResult != MPI_SUCCESS)
494 {
495 ERROR("failed to receive acknowledge for MpiOpExec from nodeId " <<
496 i << ": result = " << (int) recvResult);
497 return recvResult;
498 }
499 }
500 startCount = 0;
501 }
502
503 return MPI_SUCCESS;
504}
505
507 const void *packet,
508 const Size size) const
509{
510 DEBUG("nodeId = " << nodeId << " size = " << size);
511
512 const Node *node = m_nodes.get(nodeId);
513 if (node == ZERO)
514 {
515 ERROR("nodeId " << nodeId << " not found");
516 return MPI_ERR_ARG;
517 }
518
519 // Prepare UDP broadcast datagram
520 struct sockaddr_in addr;
521 addr.sin_family = AF_INET;
522 addr.sin_addr.s_addr = node->ipAddress;
523 addr.sin_port = htons(node->udpPort);
524
525 // Send the packet
526 int result = ::sendto(m_sock, packet, size, 0,
527 (const sockaddr *) &addr, sizeof(addr));
528 if (result <= 0)
529 {
530 ERROR("failed to send UDP datagram: " << strerror(errno));
531 return MPI_ERR_IO;
532 }
533
534 return MPI_SUCCESS;
535}
536
538 const MpiProxy::Operation operation,
539 void *packet,
540 Size & size)
541{
542 // Lookup the given node
543 const Node *node = m_nodes.get(nodeId);
544 if (node == ZERO)
545 {
546 ERROR("nodeId " << nodeId << " not found");
547 return MPI_ERR_ARG;
548 }
549
550 in_addr nodeAddr;
551 nodeAddr.s_addr = node->ipAddress;
552 DEBUG("nodeId = " << nodeId << " addr = " << inet_ntoa(nodeAddr) <<
553 " operation = " << (int) operation << " size = " << size);
554
555 // Process buffered packets first
556 for (ListIterator<Packet *> i(m_packetBuffers[nodeId]); i.hasCurrent(); i++)
557 {
558 Packet *pkt = i.current();
559 const MpiProxy::Header *hdr = (const MpiProxy::Header *) pkt->data;
560
561 if (hdr->operation == operation)
562 {
563 MemoryBlock::copy(packet, pkt->data, pkt->size);
564 size = pkt->size;
565 delete[] pkt->data;
566 delete pkt;
567 i.remove();
568 return MPI_SUCCESS;
569 }
570 }
571
572
573 // Keep receiving new packets until we have a matching packet
574 while (true)
575 {
576 struct sockaddr_in addr;
577 socklen_t len = sizeof(addr);
578 const Size recvSize = size;
579
580 // Receive UDP datagram
581 int r = recvfrom(m_sock, packet, recvSize, 0,
582 (struct sockaddr *) &addr, &len);
583 if (r < 0)
584 {
585 ERROR("failed to receive UDP datagram on socket " << m_sock << ": " << strerror(errno));
586 return MPI_ERR_IO;
587 }
588
589 const MpiProxy::Header *hdr = (const MpiProxy::Header *) packet;
590
591 DEBUG("received " << r << " bytes from " << inet_ntoa(addr.sin_addr) <<
592 ":" << htons(addr.sin_port) << " with coreId = " << hdr->coreId <<
593 " rankId = " << hdr->rankId);
594
595 // Is this packet targeted for the given node?
596 if (addr.sin_addr.s_addr == node->ipAddress &&
597 htons(addr.sin_port) == node->udpPort &&
598 hdr->coreId == node->coreId)
599 {
600 // Verify the MPI operation
601 if (hdr->operation != operation)
602 {
603 ERROR("invalid MPI operation received in packet from node" << nodeId <<
604 " (" << inet_ntoa(nodeAddr) << "): " << (int) hdr->operation <<
605 " != " << (int) operation);
606 return MPI_ERR_IO;
607 }
608
609 DEBUG("done");
610 size = r;
611 return MPI_SUCCESS;
612 }
613 // Add the packet to internal buffers for later retrieval
614 else
615 {
616 Size otherNodeId = 0;
617
618 // Find the corresponding node
619 for (Size i = 0; i < m_nodes.count(); i++)
620 {
621 if (addr.sin_addr.s_addr == m_nodes[i]->ipAddress &&
622 htons(addr.sin_port) == m_nodes[i]->udpPort &&
623 hdr->coreId == m_nodes[i]->coreId)
624 {
625 otherNodeId = i;
626 break;
627 }
628 }
629
630 if (otherNodeId == 0)
631 {
632 ERROR("nodeId not found for packet from " << inet_ntoa(addr.sin_addr) <<
633 " at port " << htons(addr.sin_port));
634 }
635 else
636 {
637 Packet *pkt = new Packet;
638 if (!pkt)
639 {
640 ERROR("failed to allocate Packet struct for buffering: " << strerror(errno));
641 return MPI_ERR_NO_MEM;
642 }
643
644 pkt->data = new u8[r];
645 if (!pkt->data)
646 {
647 ERROR("failed to allocate memory for buffered packet: " << strerror(errno));
648 return MPI_ERR_NO_MEM;
649 }
650
651 MemoryBlock::copy(pkt->data, hdr, r);
652 pkt->size = r;
653 m_packetBuffers[otherNodeId]->append(pkt);
654 }
655 }
656 }
657
658 return MPI_SUCCESS;
659}
u64 fp
Definition ARM64Control.h:3
SystemDescriptorHeader header
Definition IntelACPI.h:0
u8 coreId
Definition IntelACPI.h:1
static T * create()
Abstract function to create an instance of T.
Iterate through a List.
virtual bool hasCurrent() const
Check if there is a current item on the List.
Simple linked list template class.
Definition List.h:37
Size count() const
Get the number of items on the list.
Definition List.h:402
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
Represents a Message Passing Interface (MPI) implementation backend.
Definition MpiBackend.h:37
int Result
Result code.
Definition MpiBackend.h:47
Implements a MPI backend for the host OS which communicates with mpiproxy servers.
Definition MpiHost.h:40
Result startProcesses(int argc, char **argv)
Start remote processes.
Definition MpiHost.cpp:418
MpiHost()
Constructor.
Definition MpiHost.cpp:37
Index< List< Packet * >, MaximumNodes > m_packetBuffers
Buffers incoming packets for later processing.
Definition MpiHost.h:213
virtual Result initialize(int *argc, char ***argv)
Initialize the backend.
Definition MpiHost.cpp:41
Index< Node, MaximumNodes > m_nodes
Contains all known nodes that participate in the computation.
Definition MpiHost.h:210
int m_sock
UDP socket for communicating with remote nodes.
Definition MpiHost.h:207
virtual Result getCommRank(MPI_Comm comm, int *rank)
Retrieve communication rank (core id)
Definition MpiHost.cpp:156
Result parseHostsFile(const char *hostsfile)
Parse the given hosts file.
Definition MpiHost.cpp:315
virtual Result send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
Synchronous send data.
Definition MpiHost.cpp:170
virtual Result getCommSize(MPI_Comm comm, int *size)
Retrieve communication size (total cores)
Definition MpiHost.cpp:163
virtual Result receive(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
Synchronous receive data.
Definition MpiHost.cpp:236
virtual Result terminate()
Terminate the backend.
Definition MpiHost.cpp:105
Result receivePacket(const Size nodeId, const MpiProxy::Operation operation, void *packet, Size &size)
Receive UDP packet from remote node.
Definition MpiHost.cpp:537
Result sendPacket(const Size nodeId, const void *packet, const Size size) const
Send UDP packet to a remote node.
Definition MpiHost.cpp:506
Operation
Encodes various MPI operations.
Definition MpiProxy.h:72
@ MpiOpRecv
Definition MpiProxy.h:74
@ MpiOpSend
Definition MpiProxy.h:73
@ MpiOpTerminate
Definition MpiProxy.h:76
@ MpiOpExec
Definition MpiProxy.h:75
static const Size MaximumPacketSize
Maximum size of packet payload.
Definition MpiProxy.h:66
Abstraction of strings.
Definition String.h:42
Size length() const
Same as count().
Definition String.cpp:105
List< String > split(const char delimiter) const
Split the String into parts separated by a delimiter.
Definition String.cpp:408
MPI_Datatype
Named Predefined Datatypes.
Definition mpi.h:47
uint MPI_Status
Status holder.
Definition mpi.h:41
uint MPI_Comm
Communicator identifier.
Definition mpi.h:38
@ MPI_UNSIGNED_CHAR
Definition mpi.h:52
@ MPI_INT
Definition mpi.h:51
@ MPI_ERR_UNSUPPORTED_DATAREP
Definition mpi.h:128
@ MPI_ERR_RANK
Definition mpi.h:79
@ MPI_ERR_ARG
Definition mpi.h:86
@ MPI_SUCCESS
Definition mpi.h:73
@ MPI_ERR_IO
Definition mpi.h:108
@ MPI_ERR_NO_MEM
Definition mpi.h:112
C int atoi(const char *nptr)
Convert a string to an integer.
Definition atoi.cpp:21
C char * strerror(int errnum)
The strerror function maps the number in errnum to a message string.
Definition strerror.cpp:20
C int errno
The lvalue errno is used by many functions to return error values.
C void * memset(void *dest, int ch, size_t count)
Fill memory with a constant byte.
Definition memset.cpp:20
C int sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen)
Send a single datagram to a remote host.
Definition sendto.cpp:25
C int recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t addrlen)
Receive a single datagram from a socket.
Definition recvfrom.cpp:25
C char * basename(char *path)
Return the last component of a pathname.
Definition basename.cpp:21
C int fclose(FILE *stream)
Close a stream.
Definition fclose.cpp:23
C size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream)
Binary input.
Definition fread.cpp:24
Size socklen_t
Definition socket.h:50
C FILE * fopen(const char *filename, const char *mode)
Open a stream.
Definition fopen.cpp:24
#define NULL
NULL means zero.
Definition Macros.h:39
#define ERROR(msg)
Output an error message.
Definition Log.h:61
#define NOTICE(msg)
Output a notice message.
Definition Log.h:75
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
#define DEBUG(msg)
Output a debug message to standard output.
Definition Log.h:89
unsigned char u8
Unsigned 8-bit number.
Definition Types.h:59
A structure containing information about a file.
Definition stdio.h:61
Describes a remote CPU node accessible via MPI.
Definition MpiHost.h:52
in_addr_t ipAddress
Definition MpiHost.h:53
u32 coreId
< UDP port of the node
Definition MpiHost.h:55
u16 udpPort
< IP address of the node
Definition MpiHost.h:54
Describes data received via UDP.
Definition MpiHost.h:62
Size size
< Payload data
Definition MpiHost.h:64
Packet payload header for MPI messages via IP/UDP.
Definition MpiProxy.h:83
Defines a socket address and port pair.
Definition socket.h:36
The <sys/stat.h> header shall define the stat structure.
Definition stat.h:177
off_t st_size
For regular files, the file size in bytes.
Definition stat.h:226