Add mechanism to measure when broadcast finished execution
This commit is contained in:
parent
da6d2f3e6f
commit
21124b2613
102
finishedSignal.py
Executable file
102
finishedSignal.py
Executable file
@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
import selectors
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
class FinishedSignal:
|
||||||
|
def __init__(self, host, port, waitFor, printer=None):
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
|
self.waitFor = waitFor
|
||||||
|
self.printer = printer
|
||||||
|
self.connections = dict()
|
||||||
|
self.endTimes = dict()
|
||||||
|
self.sel = selectors.DefaultSelector()
|
||||||
|
|
||||||
|
def listen(self):
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
self.sock.bind((self.host, self.port))
|
||||||
|
self.sock.listen(128)
|
||||||
|
self.sock.setblocking(False)
|
||||||
|
self.sel.register(self.sock, selectors.EVENT_READ, self.accept)
|
||||||
|
|
||||||
|
def wait(self):
|
||||||
|
while self.waitFor > 0:
|
||||||
|
events = self.sel.select()
|
||||||
|
for key, mask in events:
|
||||||
|
callback = key.data
|
||||||
|
callback(key.fileobj, mask)
|
||||||
|
|
||||||
|
for key, pid_timestamp in self.connections.items():
|
||||||
|
pid = pid_timestamp[0]
|
||||||
|
ts = pid_timestamp[1]
|
||||||
|
self.endTimes[pid] = ts
|
||||||
|
|
||||||
|
def endTimestamps(self):
|
||||||
|
return self.endTimes
|
||||||
|
|
||||||
|
def accept(self, sock, mask):
|
||||||
|
conn, addr = sock.accept()
|
||||||
|
conn.setblocking(False)
|
||||||
|
self.sel.register(conn, selectors.EVENT_READ, self.read)
|
||||||
|
|
||||||
|
def read(self, conn, mask):
|
||||||
|
data = conn.recv(8)
|
||||||
|
if data:
|
||||||
|
pid = struct.unpack('!Q', bytes(data))[0]
|
||||||
|
self.connections[conn] = [pid]
|
||||||
|
|
||||||
|
if self.printer:
|
||||||
|
host, port = conn.getpeername()
|
||||||
|
addr = '{}:{}'.format(host, port)
|
||||||
|
self.printer("Connection from {}, corresponds to PID {}".format(addr, pid))
|
||||||
|
else:
|
||||||
|
self.connections[conn].append(int(time.time() * 1000))
|
||||||
|
self.sel.unregister(conn)
|
||||||
|
conn.close()
|
||||||
|
self.waitFor -= 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--host",
|
||||||
|
default="0.0.0.0",
|
||||||
|
dest="host",
|
||||||
|
help="IP address where the finish signal listens to (default: any)",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--port",
|
||||||
|
default=11000,
|
||||||
|
type=int,
|
||||||
|
dest="port",
|
||||||
|
help="TCP port where the finish signal listens to (default: 11000)",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
"--processes",
|
||||||
|
required=True,
|
||||||
|
type=int,
|
||||||
|
dest="processes",
|
||||||
|
help="Number of processes the finish signal waits for",
|
||||||
|
)
|
||||||
|
|
||||||
|
results = parser.parse_args()
|
||||||
|
|
||||||
|
signal = FinishedSignal(results.host, results.port, results.processes, print)
|
||||||
|
signal.listen()
|
||||||
|
print("Finish signal listens on {}:{} and waits for {} processes".format(results.host, results.port, results.processes))
|
||||||
|
|
||||||
|
signal.wait()
|
||||||
|
|
||||||
|
for pid, endTs in OrderedDict(sorted(signal.endTimestamps().items())).items():
|
||||||
|
print("Process {} finished broadcasting at time {} ms from Unix epoch ".format(pid, endTs))
|
@ -1,32 +1,90 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
|
|
||||||
void waitOnBarrier(Parser::Host const &barrier);
|
#include <endian.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
void waitOnBarrier(Parser::Host const &barrier) {
|
class Coordinator {
|
||||||
struct sockaddr_in server;
|
public:
|
||||||
std::memset(&server, 0, sizeof(server));
|
Coordinator(unsigned long id, Parser::Host barrier, Parser::Host signal)
|
||||||
|
: id_{id}, barrier_{barrier}, signal_{signal}
|
||||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
{
|
||||||
if (fd < 0) {
|
signalFd_ = connectToHost(signal_, "signal");
|
||||||
throw std::runtime_error("Could not create the barrier socket: " +
|
|
||||||
std::string(std::strerror(errno)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server.sin_family = AF_INET;
|
void waitOnBarrier() {
|
||||||
server.sin_addr.s_addr = barrier.ip;
|
int fd = connectToHost(barrier_, "barrier");
|
||||||
server.sin_port = barrier.port;
|
|
||||||
if (connect(fd, reinterpret_cast<struct sockaddr *>(&server),
|
char dummy;
|
||||||
sizeof(server)) < 0) {
|
if (recv(fd, &dummy, sizeof(dummy), 0) < 0) {
|
||||||
throw std::runtime_error("Could not connect to the barrier: " +
|
throw std::runtime_error("Could not read from the barrier socket: " +
|
||||||
std::string(std::strerror(errno)));
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
char dummy;
|
void finishedBroadcasting() {
|
||||||
if (recv(fd, &dummy, sizeof(dummy), 0) < 0) {
|
close(signalFd_);
|
||||||
throw std::runtime_error("Could not read from the barrier socket: " +
|
|
||||||
std::string(std::strerror(errno)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
private:
|
||||||
}
|
int connectToHost(Parser::Host const &host, std::string const &reason) {
|
||||||
|
struct sockaddr_in server;
|
||||||
|
std::memset(&server, 0, sizeof(server));
|
||||||
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
throw std::runtime_error("Could not create the " + reason + " socket: " +
|
||||||
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
server.sin_family = AF_INET;
|
||||||
|
server.sin_addr.s_addr = host.ip;
|
||||||
|
server.sin_port = host.port;
|
||||||
|
if (connect(fd, reinterpret_cast<struct sockaddr *>(&server),
|
||||||
|
sizeof(server)) < 0) {
|
||||||
|
throw std::runtime_error("Could not connect to the " + reason + ": " +
|
||||||
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto id = htonT(static_cast<uint64_t>(id_));
|
||||||
|
if (writeWithRetry(fd, reinterpret_cast<uint8_t *>(&id), sizeof(id))) {
|
||||||
|
throw std::runtime_error("Could not send my LogicalPID to the " + reason + ": " +
|
||||||
|
std::string(std::strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From https://stackoverflow.com/questions/32683086/handling-incomplete-write-calls
|
||||||
|
ssize_t writeWithRetry (int fd, uint8_t const* buf, size_t size) {
|
||||||
|
ssize_t ret;
|
||||||
|
while (size > 0) {
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = write(fd, buf, size);
|
||||||
|
} while ((ret < 0) && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
size -= ret;
|
||||||
|
buf += ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr T htonT (T value) noexcept
|
||||||
|
{
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
char* ptr = reinterpret_cast<char*>(&value);
|
||||||
|
std::reverse(ptr, ptr + sizeof(T));
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned long id_;
|
||||||
|
Parser::Host barrier_;
|
||||||
|
Parser::Host signal_;
|
||||||
|
int signalFd_;
|
||||||
|
};
|
||||||
|
@ -118,6 +118,11 @@ public:
|
|||||||
return barrier_;
|
return barrier_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Host signal() const {
|
||||||
|
checkParsed();
|
||||||
|
return signal_;
|
||||||
|
}
|
||||||
|
|
||||||
const char *outputPath() const {
|
const char *outputPath() const {
|
||||||
checkParsed();
|
checkParsed();
|
||||||
return outputPath_.c_str();
|
return outputPath_.c_str();
|
||||||
@ -204,6 +209,10 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!parseSignal()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parseOutputPath()) {
|
if (!parseOutputPath()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -218,7 +227,7 @@ private:
|
|||||||
void help(const int, char const *const *argv) {
|
void help(const int, char const *const *argv) {
|
||||||
auto configStr = "CONFIG";
|
auto configStr = "CONFIG";
|
||||||
std::cerr << "Usage: " << argv[0]
|
std::cerr << "Usage: " << argv[0]
|
||||||
<< " --id ID --hosts HOSTS --barrier NAME:PORT --output OUTPUT";
|
<< " --id ID --hosts HOSTS --barrier NAME:PORT --signal NAME:PORT --output OUTPUT";
|
||||||
|
|
||||||
if (!withConfig) {
|
if (!withConfig) {
|
||||||
std::cerr << "\n";
|
std::cerr << "\n";
|
||||||
@ -287,13 +296,36 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseOutputPath() {
|
bool parseSignal() {
|
||||||
if (argc < 9) {
|
if (argc < 9) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::strcmp(argv[7], "--output") == 0) {
|
if (std::strcmp(argv[7], "--signal") == 0) {
|
||||||
outputPath_ = std::string(argv[8]);
|
std::string signal_addr = argv[8];
|
||||||
|
std::replace(signal_addr.begin(), signal_addr.end(), ':', ' ');
|
||||||
|
std::stringstream ss(signal_addr);
|
||||||
|
|
||||||
|
std::string signal_name;
|
||||||
|
unsigned short signal_port;
|
||||||
|
|
||||||
|
ss >> signal_name;
|
||||||
|
ss >> signal_port;
|
||||||
|
|
||||||
|
signal_ = Host(0, signal_name, signal_port);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseOutputPath() {
|
||||||
|
if (argc < 11) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strcmp(argv[9], "--output") == 0) {
|
||||||
|
outputPath_ = std::string(argv[10]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,11 +337,11 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc < 10) {
|
if (argc < 12) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
configPath_ = std::string(argv[9]);
|
configPath_ = std::string(argv[11]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,6 +384,7 @@ private:
|
|||||||
unsigned long id_;
|
unsigned long id_;
|
||||||
std::string hostsPath_;
|
std::string hostsPath_;
|
||||||
Host barrier_;
|
Host barrier_;
|
||||||
|
Host signal_;
|
||||||
std::string outputPath_;
|
std::string outputPath_;
|
||||||
std::string configPath_;
|
std::string configPath_;
|
||||||
};
|
};
|
||||||
|
@ -69,6 +69,15 @@ int main(int argc, char **argv) {
|
|||||||
std::cout << "Machine-readbale Port: " << barrier.port << "\n";
|
std::cout << "Machine-readbale Port: " << barrier.port << "\n";
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Signal:\n";
|
||||||
|
std::cout << "========\n";
|
||||||
|
auto signal = parser.signal();
|
||||||
|
std::cout << "Human-readable IP: " << signal.ipReadable() << "\n";
|
||||||
|
std::cout << "Machine-readable IP: " << signal.ip << "\n";
|
||||||
|
std::cout << "Human-readbale Port: " << signal.portReadable() << "\n";
|
||||||
|
std::cout << "Machine-readbale Port: " << signal.port << "\n";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
std::cout << "Path to output:\n";
|
std::cout << "Path to output:\n";
|
||||||
std::cout << "===============\n";
|
std::cout << "===============\n";
|
||||||
std::cout << parser.outputPath() << "\n\n";
|
std::cout << parser.outputPath() << "\n\n";
|
||||||
@ -81,11 +90,17 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
std::cout << "Doing some initialization...\n\n";
|
std::cout << "Doing some initialization...\n\n";
|
||||||
|
|
||||||
|
Coordinator coordinator(parser.id(), barrier, signal);
|
||||||
|
|
||||||
std::cout << "Waiting for all processes to finish initialization\n\n";
|
std::cout << "Waiting for all processes to finish initialization\n\n";
|
||||||
waitOnBarrier(barrier);
|
coordinator.waitOnBarrier();
|
||||||
|
|
||||||
std::cout << "Broadcasting messages...\n\n";
|
std::cout << "Broadcasting messages...\n\n";
|
||||||
|
|
||||||
|
std::cout << "Signaling end of broadcasting messages\n\n";
|
||||||
|
coordinator.finishedBroadcasting();
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(60));
|
std::this_thread::sleep_for(std::chrono::seconds(60));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user