From 6db4242dd38a91e21bfa44c2d2ec706a4513c2e1 Mon Sep 17 00:00:00 2001 From: Alexander van Amesfoort <amesfoort@astron.nl> Date: Thu, 3 Aug 2017 01:12:02 +0000 Subject: [PATCH] Task #5441: COBALT RSP raw support: initial mega commit to LCS/Stream and RTCP/Cobalt --- LCS/Common/include/Common/Thread/Semaphore.h | 8 + .../Stream/FileDescriptorBasedStream.h | 10 +- LCS/Stream/include/Stream/FileStream.h | 4 +- LCS/Stream/include/Stream/FixedBufferStream.h | 9 +- LCS/Stream/include/Stream/NamedPipeStream.h | 8 +- LCS/Stream/include/Stream/NullStream.h | 7 +- .../include/Stream/SharedMemoryStream.h | 6 +- LCS/Stream/include/Stream/SocketStream.h | 26 +- LCS/Stream/include/Stream/Stream.h | 6 +- LCS/Stream/include/Stream/StringStream.h | 5 +- LCS/Stream/src/FileDescriptorBasedStream.cc | 47 +++- LCS/Stream/src/FixedBufferStream.cc | 65 ++++- LCS/Stream/src/NamedPipeStream.cc | 14 +- LCS/Stream/src/NullStream.cc | 35 ++- LCS/Stream/src/SharedMemoryStream.cc | 14 +- LCS/Stream/src/SocketStream.cc | 67 ++++- LCS/Stream/src/StringStream.cc | 78 +++++- RTCP/Cobalt/CoInterface/src/CMakeLists.txt | 1 + RTCP/Cobalt/CoInterface/src/CorrelatedData.h | 1 - RTCP/Cobalt/CoInterface/src/OutputTypes.h | 6 +- RTCP/Cobalt/CoInterface/src/Parset.cc | 235 ++++++++++++++---- RTCP/Cobalt/CoInterface/src/Parset.h | 107 +++++++- .../src/Station => CoInterface/src}/RSP.h | 29 +-- RTCP/Cobalt/CoInterface/src/RSPRawTransfer.cc | 207 +++++++++++++++ RTCP/Cobalt/CoInterface/src/RSPRawTransfer.h | 84 +++++++ RTCP/Cobalt/CoInterface/src/Stream.cc | 1 + RTCP/Cobalt/CoInterface/src/StreamableData.h | 67 ++++- RTCP/Cobalt/CoInterface/test/CMakeLists.txt | 1 + .../CoInterface/test/tRSPRawTransfer.cc | 76 ++++++ RTCP/Cobalt/GPUProc/etc/CMakeLists.txt | 4 + .../default/HardwareList.parset | 183 ++++++++++++-- .../default/HardwareUsed.parset | 23 ++ .../rspraw-enable.parset.OBSID | 58 +++++ RTCP/Cobalt/GPUProc/src/MPIReceiver.h | 4 +- .../GPUProc/src/Station/StationInput.cc | 151 +++++++---- .../Cobalt/GPUProc/src/Station/StationInput.h | 22 +- .../GPUProc/src/Station/StationTranspose.h | 2 +- .../GPUProc/src/cuda/Pipelines/Pipeline.cc | 5 +- RTCP/Cobalt/GPUProc/src/rtcp.cc | 26 +- .../GPUProc/src/scripts/cobalt_functions.sh | 2 +- RTCP/Cobalt/GPUProc/test/tMPIReceive.cc | 2 +- RTCP/Cobalt/InputProc/src/Station/Generator.h | 2 +- .../InputProc/src/Station/PacketFactory.h | 3 +- .../InputProc/src/Station/PacketReader.cc | 16 +- .../InputProc/src/Station/PacketReader.h | 19 +- .../InputProc/src/Station/PacketStream.h | 76 +++++- .../Cobalt/InputProc/src/Station/filterRSP.cc | 2 +- .../InputProc/src/Station/generateRSP.cc | 2 +- RTCP/Cobalt/InputProc/src/Station/printRSP.cc | 3 +- .../Cobalt/InputProc/src/Station/repairRSP.cc | 2 +- RTCP/Cobalt/InputProc/test/tPacketReader.cc | 2 +- RTCP/Cobalt/InputProc/test/tRSP.cc | 2 +- RTCP/Cobalt/OutputProc/src/CMakeLists.txt | 1 + .../OutputProc/src/CommonLofarAttributes.cc | 2 +- RTCP/Cobalt/OutputProc/src/GPUProcIO.cc | 64 ++++- RTCP/Cobalt/OutputProc/src/GPUProcIO.h | 5 +- RTCP/Cobalt/OutputProc/src/InputThread.cc | 14 +- RTCP/Cobalt/OutputProc/src/InputThread.h | 10 +- RTCP/Cobalt/OutputProc/src/MSWriterFile.cc | 5 +- RTCP/Cobalt/OutputProc/src/MSWriterNull.cc | 2 +- RTCP/Cobalt/OutputProc/src/OutputThread.cc | 145 +++++++---- RTCP/Cobalt/OutputProc/src/OutputThread.h | 19 +- RTCP/Cobalt/OutputProc/src/RSPRawWriter.cc | 93 +++++++ RTCP/Cobalt/OutputProc/src/RSPRawWriter.h | 75 ++++++ RTCP/Cobalt/OutputProc/src/SubbandWriter.cc | 11 +- RTCP/Cobalt/OutputProc/src/SubbandWriter.h | 6 +- RTCP/Cobalt/OutputProc/src/plotMS.cc | 2 +- RTCP/Cobalt/OutputProc/test/tSubbandWriter.cc | 4 +- 68 files changed, 1966 insertions(+), 327 deletions(-) rename RTCP/Cobalt/{InputProc/src/Station => CoInterface/src}/RSP.h (91%) create mode 100644 RTCP/Cobalt/CoInterface/src/RSPRawTransfer.cc create mode 100644 RTCP/Cobalt/CoInterface/src/RSPRawTransfer.h create mode 100644 RTCP/Cobalt/CoInterface/test/tRSPRawTransfer.cc create mode 100644 RTCP/Cobalt/GPUProc/etc/parset-additions.d/rspraw-enable.parset.OBSID create mode 100644 RTCP/Cobalt/OutputProc/src/RSPRawWriter.cc create mode 100644 RTCP/Cobalt/OutputProc/src/RSPRawWriter.h diff --git a/LCS/Common/include/Common/Thread/Semaphore.h b/LCS/Common/include/Common/Thread/Semaphore.h index 3bb01ecadee..a9571e2e22b 100644 --- a/LCS/Common/include/Common/Thread/Semaphore.h +++ b/LCS/Common/include/Common/Thread/Semaphore.h @@ -42,6 +42,7 @@ class Semaphore bool tryDown(unsigned count = 1); bool tryDown(unsigned count, const struct timespec ×pec); + unsigned getValue(); void noMore(); private: @@ -114,6 +115,13 @@ inline bool Semaphore::tryDown(unsigned count, const struct timespec ×pec) } +inline unsigned Semaphore::getValue() +{ + ScopedLock lock(mutex); // w/ C++11, we can use memory_order_relaxed instead + return level; +} + + inline void Semaphore::noMore() { ScopedLock lock(mutex); diff --git a/LCS/Stream/include/Stream/FileDescriptorBasedStream.h b/LCS/Stream/include/Stream/FileDescriptorBasedStream.h index 8b46090e947..1682651b1a0 100644 --- a/LCS/Stream/include/Stream/FileDescriptorBasedStream.h +++ b/LCS/Stream/include/Stream/FileDescriptorBasedStream.h @@ -1,6 +1,6 @@ //# FileDescriptorBasedStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -37,8 +37,16 @@ class FileDescriptorBasedStream : public Stream virtual size_t tryRead(void *ptr, size_t size); virtual size_t tryWrite(const void *ptr, size_t size); + virtual size_t tryReadv(const struct iovec *iov, int iovcnt); + virtual size_t tryWritev(const struct iovec *iov, int iovcnt); + virtual void sync(); + // Apart from int, fcntl can also be called with an arg of type struct flock *, or struct f_owner_ex * + int fcntl(int cmd); + int fcntl(int cmd, int arg); + + int fd; }; diff --git a/LCS/Stream/include/Stream/FileStream.h b/LCS/Stream/include/Stream/FileStream.h index ee2cb7f3eeb..db905d9e8ac 100644 --- a/LCS/Stream/include/Stream/FileStream.h +++ b/LCS/Stream/include/Stream/FileStream.h @@ -1,6 +1,6 @@ //# FileStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2015-2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -40,7 +40,7 @@ class FileStream : public FileDescriptorBasedStream virtual void skip( size_t bytes ); // seek ahead - virtual size_t size(); // return file size + size_t size(); // return file size }; } // namespace LOFAR diff --git a/LCS/Stream/include/Stream/FixedBufferStream.h b/LCS/Stream/include/Stream/FixedBufferStream.h index 40d0763aeff..1116043f876 100644 --- a/LCS/Stream/include/Stream/FixedBufferStream.h +++ b/LCS/Stream/include/Stream/FixedBufferStream.h @@ -1,6 +1,6 @@ //# FixedBufferStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -32,6 +32,10 @@ namespace LOFAR { // no wrap-around support! // not thread safe! +// Note that an object represents a reader xor writer, not the buffer. +// which is passed in. To use it, reader and writer each create an object passing the same buffer. +// The reader may (at its own peril) overtake the writer. (I don't get what's the use of this semantic.) + class FixedBufferStream : public Stream { public: @@ -41,6 +45,9 @@ class FixedBufferStream : public Stream virtual size_t tryRead(void *ptr, size_t size); virtual size_t tryWrite(const void *ptr, size_t size); + virtual size_t tryReadv(const struct iovec *iov, int iovcnt); + virtual size_t tryWritev(const struct iovec *iov, int iovcnt); + private: char * const itsEnd; diff --git a/LCS/Stream/include/Stream/NamedPipeStream.h b/LCS/Stream/include/Stream/NamedPipeStream.h index 2980859e041..4e820936b22 100644 --- a/LCS/Stream/include/Stream/NamedPipeStream.h +++ b/LCS/Stream/include/Stream/NamedPipeStream.h @@ -1,6 +1,6 @@ //# NamedPipeStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -36,7 +36,11 @@ class NamedPipeStream : public Stream NamedPipeStream(const char *name, bool serverSide); virtual ~NamedPipeStream(); - virtual size_t tryRead(void *, size_t), tryWrite(const void *, size_t); + virtual size_t tryRead(void *ptr, size_t size); + virtual size_t tryWrite(const void *ptr, size_t size); + + virtual size_t tryReadv(const struct iovec *iov, int iovcnt); + virtual size_t tryWritev(const struct iovec *iov, int iovcnt); virtual void sync(); diff --git a/LCS/Stream/include/Stream/NullStream.h b/LCS/Stream/include/Stream/NullStream.h index 96e5086bd21..5e373facb29 100644 --- a/LCS/Stream/include/Stream/NullStream.h +++ b/LCS/Stream/include/Stream/NullStream.h @@ -1,6 +1,6 @@ //# NullStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -25,8 +25,6 @@ #include <Stream/Stream.h> -#include <errno.h> - namespace LOFAR { @@ -37,6 +35,9 @@ class NullStream : public Stream virtual size_t tryRead(void *ptr, size_t size); virtual size_t tryWrite(const void *ptr, size_t size); + + virtual size_t tryReadv(const struct iovec *iov, int iovcnt); + virtual size_t tryWritev(const struct iovec *iov, int iovcnt); }; } // namespace LOFAR diff --git a/LCS/Stream/include/Stream/SharedMemoryStream.h b/LCS/Stream/include/Stream/SharedMemoryStream.h index 90af7b83201..cf259f57921 100644 --- a/LCS/Stream/include/Stream/SharedMemoryStream.h +++ b/LCS/Stream/include/Stream/SharedMemoryStream.h @@ -1,6 +1,6 @@ //# SharedMemoryStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -39,6 +39,10 @@ class SharedMemoryStream : public Stream virtual size_t tryRead(void *ptr, size_t size); virtual size_t tryWrite(const void *ptr, size_t size); + // these 2 throw a NotImplemented exception + virtual size_t tryReadv(const struct iovec *iov, int iovcnt); + virtual size_t tryWritev(const struct iovec *iov, int iovcnt); + private: Mutex readLock, writeLock; Semaphore readDone, writePosted; diff --git a/LCS/Stream/include/Stream/SocketStream.h b/LCS/Stream/include/Stream/SocketStream.h index d26495c1337..730552a65d3 100644 --- a/LCS/Stream/include/Stream/SocketStream.h +++ b/LCS/Stream/include/Stream/SocketStream.h @@ -1,6 +1,6 @@ //# SocketStream.h: //# -//# Copyright (C) 2008, 2015 +//# Copyright (C) 2008, 2015-2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -59,20 +59,34 @@ class SocketStream : public FileDescriptorBasedStream const Protocol protocol; const Mode mode; + /* + * Send message(s). Note: only for UDP client socket! + * @bufBase contains all messages to be sent. It may have gaps, but all of the same size. + * @msgSize indicates the (common) size of each individual message. + * @sentMsgSizes length indicates the (maximum) number of messages to send. + * Note: the Linux sendmmsg(2) man page indicates this is capped to UIO_MAXIOV (1024). + * The actually sent sizes per message will be written into this argument. + * @flags: passed to sendmsg(2)/sendmmsg(2). For some of our cases, we want to always pass MSG_CONFIRM. + * Returns the number of messages sent if ok, or throws on syscall error. + */ + unsigned sendmmsg( void *bufBase, size_t msgSize, + std::vector<unsigned> &sentMsgSizes, int flags ) const; + /* * Receive message(s). Note: only for UDP server socket! * @bufBase is large enough to store all to be received messages - * @maxMsgSize indicates the max size of _each_ (i.e. 1) message - * @recvdMsgSizes is passed in with a size indicating the max number of - * messages to receive. Actually received sizes will be written therein. + * @maxMsgSize indicates the max size of each individual message + * @recvdMsgSizes length indicates the maximum number of messages to receive. + * The actually received sizes per message will be written into this argument. * Returns the number of messages received if ok, or throws on syscall error */ - unsigned recvmmsg( void *bufBase, unsigned maxMsgSize, + unsigned recvmmsg( void *bufBase, size_t maxMsgSize, std::vector<unsigned> &recvdMsgSizes ) const; - // Allow individual recv()/send() calls to last for 'timeout' seconds before returning EWOULDBLOCK + // Allow individual recv()/send() calls to last for 'timeout' seconds before returning EAGAIN (or EWOULDBLOCK) void setTimeout(double timeout); + std::string getHostname() const { return hostname; } int getPort() const { return port; } private: diff --git a/LCS/Stream/include/Stream/Stream.h b/LCS/Stream/include/Stream/Stream.h index 49cbf2465d2..93b7ff703c2 100644 --- a/LCS/Stream/include/Stream/Stream.h +++ b/LCS/Stream/include/Stream/Stream.h @@ -1,6 +1,6 @@ //# Stream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -24,6 +24,7 @@ #define LOFAR_LCS_STREAM_STREAM_H #include <cstddef> +#include <sys/uio.h> #include <string> #include <Common/Exception.h> @@ -42,6 +43,9 @@ class Stream virtual size_t tryWrite(const void *ptr, size_t size) = 0; void write(const void *ptr, size_t size); // does not return until all bytes are written + virtual size_t tryReadv(const struct iovec *iov, int iovcnt) = 0; + virtual size_t tryWritev(const struct iovec *iov, int iovcnt) = 0; + std::string readLine(); // excludes '\n' virtual void sync(); diff --git a/LCS/Stream/include/Stream/StringStream.h b/LCS/Stream/include/Stream/StringStream.h index c305d56a640..ba43c9150da 100644 --- a/LCS/Stream/include/Stream/StringStream.h +++ b/LCS/Stream/include/Stream/StringStream.h @@ -1,6 +1,6 @@ //# StringStream.h: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -39,6 +39,9 @@ class StringStream : public Stream virtual size_t tryRead(void *ptr, size_t size); virtual size_t tryWrite(const void *ptr, size_t size); + virtual size_t tryReadv(const struct iovec *iov, int iovcnt); + virtual size_t tryWritev(const struct iovec *iov, int iovcnt); + void close(); private: diff --git a/LCS/Stream/src/FileDescriptorBasedStream.cc b/LCS/Stream/src/FileDescriptorBasedStream.cc index ebd7a2c9074..5b6f3380533 100644 --- a/LCS/Stream/src/FileDescriptorBasedStream.cc +++ b/LCS/Stream/src/FileDescriptorBasedStream.cc @@ -1,6 +1,6 @@ //# FileDescriptorBasedStream.cc: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -25,6 +25,7 @@ #include <Stream/FileDescriptorBasedStream.h> #include <unistd.h> +#include <fcntl.h> #include <Common/SystemCallException.h> #include <Common/Thread/Cancellation.h> @@ -82,10 +83,54 @@ size_t FileDescriptorBasedStream::tryWrite(const void *ptr, size_t size) } +size_t FileDescriptorBasedStream::tryReadv(const struct iovec *iov, int iovcnt) +{ + ssize_t bytes = ::readv(fd, iov, iovcnt); + + if (bytes < 0) + THROW_SYSCALL("readv"); + + return bytes; +} + + +size_t FileDescriptorBasedStream::tryWritev(const struct iovec *iov, int iovcnt) +{ + ssize_t bytes = ::writev(fd, iov, iovcnt); + + if (bytes < 0) + THROW_SYSCALL("writev"); + + return bytes; +} + + void FileDescriptorBasedStream::sync() { if (::fsync(fd) < 0) THROW_SYSCALL("fsync"); } + +int FileDescriptorBasedStream::fcntl(int cmd) +{ + int rv = ::fcntl(fd, cmd); + + if (rv < 0) + THROW_SYSCALL("fcntl"); + + return rv; +} + + +int FileDescriptorBasedStream::fcntl(int cmd, int arg) +{ + int rv = ::fcntl(fd, cmd, arg); + + if (rv < 0) + THROW_SYSCALL("fcntl"); + + return rv; +} + } // namespace LOFAR diff --git a/LCS/Stream/src/FixedBufferStream.cc b/LCS/Stream/src/FixedBufferStream.cc index 1578ba4042b..43630a2e44a 100644 --- a/LCS/Stream/src/FixedBufferStream.cc +++ b/LCS/Stream/src/FixedBufferStream.cc @@ -1,6 +1,6 @@ //# FixedBufferStream.cc: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -48,6 +48,9 @@ size_t FixedBufferStream::tryRead(void *ptr, size_t size) { Cancellation::point(); // keep behaviour consistent with real I/O streams + if (size == 0) + return 0; + size_t numBytes = std::min<size_t>(size, itsEnd - itsHead); if (numBytes == 0) @@ -64,6 +67,9 @@ size_t FixedBufferStream::tryWrite(const void *ptr, size_t size) { Cancellation::point(); // keep behaviour consistent with real I/O streams + if (size == 0) + return 0; + size_t numBytes = std::min<size_t>(size, itsEnd - itsHead); if (numBytes == 0) @@ -75,4 +81,61 @@ size_t FixedBufferStream::tryWrite(const void *ptr, size_t size) return numBytes; } + +size_t FixedBufferStream::tryReadv(const struct iovec *iov, int iovcnt) +{ + Cancellation::point(); // keep behaviour consistent with real I/O streams + + size_t nread = 0; + + for (int i = 0; i < iovcnt; i++) { + if (iov[i].iov_len <= (size_t)(itsEnd - itsHead)) { + memcpy(iov[i].iov_base, itsHead, iov[i].iov_len); + itsHead += iov[i].iov_len; + nread += iov[i].iov_len; + } else { + if (itsEnd - itsHead == 0) { + if (nread == 0) // to be read > 0 + THROW(EndOfStreamException, "No space left in buffer"); + } else { + memcpy(iov[i].iov_base, itsHead, itsEnd - itsHead); + itsHead = itsEnd; + nread += itsEnd - itsHead; + } + break; + } + } + + return nread; +} + + +size_t FixedBufferStream::tryWritev(const struct iovec *iov, int iovcnt) +{ + Cancellation::point(); // keep behaviour consistent with real I/O streams + + size_t nwritten = 0; + + for (int i = 0; i < iovcnt; i++) { + if (iov[i].iov_len <= (size_t)(itsEnd - itsHead)) { + memcpy(itsHead, iov[i].iov_base, iov[i].iov_len); + itsHead += iov[i].iov_len; + nwritten += iov[i].iov_len; + } else { + if (itsEnd - itsHead == 0) { + if (nwritten == 0) // to be written > 0 + THROW(EndOfStreamException, "No space left in buffer"); + } else { + memcpy(itsHead, iov[i].iov_base, itsEnd - itsHead); + itsHead = itsEnd; + nwritten += itsEnd - itsHead; + } + break; + } + } + + return nwritten; +} + + } // namespace LOFAR diff --git a/LCS/Stream/src/NamedPipeStream.cc b/LCS/Stream/src/NamedPipeStream.cc index 20d7d961a22..2feca603820 100644 --- a/LCS/Stream/src/NamedPipeStream.cc +++ b/LCS/Stream/src/NamedPipeStream.cc @@ -1,6 +1,6 @@ //# NamedPipeStream.cc: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -86,6 +86,18 @@ size_t NamedPipeStream::tryWrite(const void *ptr, size_t size) } +size_t NamedPipeStream::tryReadv(const struct iovec *iov, int iovcnt) +{ + return itsReadStream->tryReadv(iov, iovcnt); +} + + +size_t NamedPipeStream::tryWritev(const struct iovec *iov, int iovcnt) +{ + return itsWriteStream->tryWritev(iov, iovcnt); +} + + void NamedPipeStream::sync() { itsWriteStream->sync(); diff --git a/LCS/Stream/src/NullStream.cc b/LCS/Stream/src/NullStream.cc index 1b6c54b3e84..24e29d5e481 100644 --- a/LCS/Stream/src/NullStream.cc +++ b/LCS/Stream/src/NullStream.cc @@ -1,6 +1,6 @@ //# NullStream.cc: //# -//# Copyright (C) 2008 +//# Copyright (C) 2008, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -23,10 +23,9 @@ #include <lofar_config.h> #include <Stream/NullStream.h> -#include <Common/Thread/Cancellation.h> #include <cstring> - +#include <Common/Thread/Cancellation.h> namespace LOFAR { @@ -51,4 +50,34 @@ size_t NullStream::tryWrite(const void *, size_t size) return size; } + +size_t NullStream::tryReadv(const struct iovec *iov, int iovcnt) +{ + Cancellation::point(); // keep behaviour consistent with non-null streams + + size_t size = 0; + + for (int i = 0; i < iovcnt; i++) { + memset(iov[i].iov_base, 0, iov[i].iov_len); + size += iov[i].iov_len; + } + + return size; +} + + +size_t NullStream::tryWritev(const struct iovec *iov, int iovcnt) +{ + Cancellation::point(); // keep behaviour consistent with non-null streams + + size_t size = 0; + + for (int i = 0; i < iovcnt; i++) { + size += iov[i].iov_len; + } + + return size; +} + + } // namespace LOFAR diff --git a/LCS/Stream/src/SharedMemoryStream.cc b/LCS/Stream/src/SharedMemoryStream.cc index e589c61da9a..921efd1d450 100644 --- a/LCS/Stream/src/SharedMemoryStream.cc +++ b/LCS/Stream/src/SharedMemoryStream.cc @@ -1,6 +1,6 @@ //# SharedMemoryStream.cc: //# -//# Copyright (C) 2012 +//# Copyright (C) 2012, 2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -61,6 +61,18 @@ size_t SharedMemoryStream::tryWrite(const void *ptr, size_t size) return readSize; } + +size_t SharedMemoryStream::tryReadv(const struct iovec * /*iov*/, int /*iovcnt*/) +{ + THROW(NotImplemented, "SharedMemoryStream::tryReadv()"); +} + + +size_t SharedMemoryStream::tryWritev(const struct iovec * /*iov*/, int /*iovcnt*/) +{ + THROW(NotImplemented, "SharedMemoryStream::tryWritev()"); +} + } // namespace LOFAR #endif diff --git a/LCS/Stream/src/SocketStream.cc b/LCS/Stream/src/SocketStream.cc index 8afb6968e39..a08f7c5dd5c 100644 --- a/LCS/Stream/src/SocketStream.cc +++ b/LCS/Stream/src/SocketStream.cc @@ -1,6 +1,6 @@ //# SocketStream.cc: //# -//# Copyright (C) 2008, 2015 +//# Copyright (C) 2008, 2015-2017 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -29,6 +29,7 @@ #include <cstdio> #include <ctime> #include <cerrno> +#include <cassert> #include <sys/types.h> #include <unistd.h> #include <sys/select.h> @@ -282,8 +283,8 @@ void SocketStream::setTimeout(double timeout) #if defined __linux__ && __GLIBC_PREREQ(2,12) -// Actually, recvmmsg is supported by Linux 2.6.32+ using glibc 2.12+ -#define HAVE_RECVMMSG +// Actually, sendmmsg and recvmmsg are supported by Linux 2.6.32+ using glibc 2.12+ +#define HAVE_MMSG #else // Equalize data structures to share more code. Declared within LOFAR namespace. // Need it as vector template arg, so cannot be locally declared (ok w/ C++11). @@ -292,17 +293,71 @@ struct mmsghdr { }; #endif -unsigned SocketStream::recvmmsg( void *bufBase, unsigned maxMsgSize, +unsigned SocketStream::sendmmsg( void *bufBase, size_t msgSize, + std::vector<unsigned> &sentMsgSizes, int flags ) const +{ + ASSERT(protocol == UDP); + ASSERT(mode == Client); + + // If sendmmsg() is not available, then use sendmsg() (1 call) as fall-back. +#ifdef HAVE_MMSG + const unsigned numBufs = sentMsgSizes.size(); +#else + const unsigned numBufs = 1; + if (sentMsgSizes.empty()) { + return 0; + } +#endif + + // register our send buffer(s) + std::vector<struct iovec> iov(numBufs); + for (unsigned i = 0; i < numBufs; i++) { + iov[i].iov_base = (char*)bufBase + i * msgSize; + iov[i].iov_len = msgSize; + } + + std::vector<struct mmsghdr> msgs(numBufs); + for (unsigned i = 0; i < numBufs; ++i) { + msgs[i].msg_hdr.msg_name = NULL; // dst address already set on socket via connect(2) + msgs[i].msg_hdr.msg_iov = &iov[i]; + msgs[i].msg_hdr.msg_iovlen = 1; + msgs[i].msg_hdr.msg_control = NULL; // we're not interested in sending OoB data + } + + int numSent; +#ifdef HAVE_MMSG + numSent = ::sendmmsg(fd, &msgs[0], numBufs, flags); + if (numSent < 0) + THROW_SYSCALL("sendmmsg"); + + for (int i = 0; i < numSent; ++i) { + sentMsgSizes[i] = msgs[i].msg_len; // num bytes sent is stored in msg_len by sendmmsg() + } +#else + numSent = ::sendmsg(fd, &msgs[0].msg_hdr, flags); + if (numSent < 0) + THROW_SYSCALL("sendmsg"); + + sentMsgSizes[0] = static_cast<unsigned>(numSent); // num bytes sent is returned by sendmsg() + numSent = 1; // equalize return val semantics to num msgs sent +#endif + return static_cast<unsigned>(numSent); +} + +unsigned SocketStream::recvmmsg( void *bufBase, size_t maxMsgSize, std::vector<unsigned> &recvdMsgSizes ) const { ASSERT(protocol == UDP); ASSERT(mode == Server); // If recvmmsg() is not available, then use recvmsg() (1 call) as fall-back. -#ifdef HAVE_RECVMMSG +#ifdef HAVE_MMSG const unsigned numBufs = recvdMsgSizes.size(); #else const unsigned numBufs = 1; + if (recvdMsgSizes.empty()) { + return 0; + } #endif // register our receive buffer(s) @@ -321,7 +376,7 @@ unsigned SocketStream::recvmmsg( void *bufBase, unsigned maxMsgSize, } int numRead; -#ifdef HAVE_RECVMMSG +#ifdef HAVE_MMSG // Note: the timeout parameter doesn't work as expected: only between datagrams // is the timeout checked, not when waiting for one (i.e. numBufs=1 or MSG_WAITFORONE). numRead = ::recvmmsg(fd, &msgs[0], numBufs, 0, NULL); diff --git a/LCS/Stream/src/StringStream.cc b/LCS/Stream/src/StringStream.cc index d629d634687..b213a18a5a5 100644 --- a/LCS/Stream/src/StringStream.cc +++ b/LCS/Stream/src/StringStream.cc @@ -40,13 +40,20 @@ size_t StringStream::tryRead(void *ptr, size_t size) { Cancellation::point(); // keep behaviour consistent with real I/O streams + { + ScopedLock sl(itsMutex); +// still wrong for !USE_THREADS wrt stringstream exception vs EndOfStreamException, but !USE_THREADS is obsolete anyway #ifdef USE_THREADS - if (!dataWritten.down(size)) - THROW(EndOfStreamException, "Stream has been closed"); + if (!dataWritten.down(size)) { + size_t avail = dataWritten.getValue(); + if (avail == 0) // size > 0 + THROW(EndOfStreamException, "Stream has been closed"); + + size = avail; + dataWritten.down(size); + } #endif - { - ScopedLock sl(itsMutex); itsBuffer.read(static_cast<char*>(ptr), size); } @@ -71,6 +78,69 @@ size_t StringStream::tryWrite(const void *ptr, size_t size) } +size_t StringStream::tryReadv(const struct iovec *iov, int iovcnt) +{ + Cancellation::point(); // keep behaviour consistent with non-null streams + + size_t size = 0; + + for (int i = 0; i < iovcnt; i++) { + size += iov[i].iov_len; + } + + { + ScopedLock sl(itsMutex); +// still wrong for !USE_THREADS wrt stringstream exception vs EndOfStreamException, but !USE_THREADS is obsolete anyway +#ifdef USE_THREADS + if (!dataWritten.down(size)) { + size_t avail = dataWritten.getValue(); + if (avail == 0) // size > 0 + THROW(EndOfStreamException, "Stream has been closed"); + + size = avail; + dataWritten.down(size); + + for (int i = 0; i < iovcnt && avail > 0; i++) { + size_t len = avail < iov[i].iov_len ? avail : iov[i].iov_len; + itsBuffer.read(static_cast<char*>(iov[i].iov_base), len); + avail -= len; + } + + return size; + } +#endif + + for (int i = 0; i < iovcnt; i++) { + itsBuffer.read(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); + } + } + + return size; +} + + +size_t StringStream::tryWritev(const struct iovec *iov, int iovcnt) +{ + Cancellation::point(); // keep behaviour consistent with non-null streams + + size_t size = 0; + + { + ScopedLock sl(itsMutex); + for (int i = 0; i < iovcnt; i++) { + itsBuffer.write(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len); + size += iov[i].iov_len; + } + } + +#ifdef USE_THREADS + dataWritten.up(size); +#endif + + return size; +} + + void StringStream::close() { #ifdef USE_THREADS diff --git a/RTCP/Cobalt/CoInterface/src/CMakeLists.txt b/RTCP/Cobalt/CoInterface/src/CMakeLists.txt index 5820f8c93da..0a9300bbc94 100644 --- a/RTCP/Cobalt/CoInterface/src/CMakeLists.txt +++ b/RTCP/Cobalt/CoInterface/src/CMakeLists.txt @@ -15,6 +15,7 @@ lofar_add_library(cointerface BudgetTimer.cc FinalMetaData.cc LTAFeedback.cc + RSPRawTransfer.cc Stream.cc Parset.cc RunningStatistics.cc diff --git a/RTCP/Cobalt/CoInterface/src/CorrelatedData.h b/RTCP/Cobalt/CoInterface/src/CorrelatedData.h index 0efe2c42eee..b191945a19c 100644 --- a/RTCP/Cobalt/CoInterface/src/CorrelatedData.h +++ b/RTCP/Cobalt/CoInterface/src/CorrelatedData.h @@ -29,7 +29,6 @@ #include <CoInterface/Config.h> #include <CoInterface/StreamableData.h> #include <CoInterface/MultiDimArray.h> -#include <CoInterface/OutputTypes.h> namespace LOFAR diff --git a/RTCP/Cobalt/CoInterface/src/OutputTypes.h b/RTCP/Cobalt/CoInterface/src/OutputTypes.h index a2280b6f80f..032701e3eac 100644 --- a/RTCP/Cobalt/CoInterface/src/OutputTypes.h +++ b/RTCP/Cobalt/CoInterface/src/OutputTypes.h @@ -1,5 +1,6 @@ //# OutputTypes.h -//# Copyright (C) 2011-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2011-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -32,7 +33,8 @@ namespace LOFAR enum OutputType { CORRELATED_DATA = 1, - BEAM_FORMED_DATA + BEAM_FORMED_DATA, + RSP_RAW_DATA }; } // namespace Cobalt diff --git a/RTCP/Cobalt/CoInterface/src/Parset.cc b/RTCP/Cobalt/CoInterface/src/Parset.cc index afbc2653015..f83a97e3ce3 100644 --- a/RTCP/Cobalt/CoInterface/src/Parset.cc +++ b/RTCP/Cobalt/CoInterface/src/Parset.cc @@ -1,5 +1,5 @@ //# Parset.cc -//# Copyright (C) 2008-2015 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2008-2017 ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -319,10 +319,11 @@ namespace LOFAR // NOTE: Make sure that all keys have defaults, to make test parsets // a lot shorter. + // --Update: No, instead use tParsetDefault in tests and reject parsets with missing required values. - vector<string> emptyVectorString; - vector<unsigned> emptyVectorUnsigned; - vector<double> emptyVectorDouble; + const vector<string> emptyVectorString; + const vector<unsigned> emptyVectorUnsigned; + const vector<double> emptyVectorDouble; // Generic information settings.realTime = getBool("Cobalt.realTime", false); @@ -498,7 +499,7 @@ namespace LOFAR string prefix = str(format("PIC.Core.Cobalt.%s.") % node.name); node.hostName = getString(prefix + "host", "localhost"); - node.cpu = getUint32(prefix + "cpu", 0); + node.cpu = getInt(prefix + "cpu", -1); node.mpi_nic = getString(prefix + "mpi_nic", ""); node.gpus = getUint32Vector(prefix + "gpus", vector<unsigned>(1,0)); // default to [0] @@ -635,35 +636,7 @@ namespace LOFAR settings.beamFormer.nrDelayCompensationChannels = nrDelayCompCh; // Derive antennaFields to use for beam forming - vector<string> beamFormerStations = getStringVector("Cobalt.BeamFormer.stationList", emptyVectorString, true); - if (beamFormerStations.empty()) { - // if [], default to all stations - beamFormerStations = stations; - } else { - // filter out stations not in the observation. This allows basic defaults ([CS002..7] etc) to be used, even if - // they contain stations that are not available. - vector<string> filteredList; - - for (size_t i = 0; i < beamFormerStations.size(); i++) { - if (std::find(stations.begin(), - stations.end(), - beamFormerStations[i]) != stations.end()) { - filteredList.push_back(beamFormerStations[i]); - } else { - LOG_WARN_STR("Removing station " << beamFormerStations[i] << " from the beam-former, as it is not participating in the observation: " << settings.rawStationList); - } - } - - beamFormerStations = filteredList; - } - - // Note that this could happen by accident if too many stations are taken out of the observation, leaving none to beam form. - ASSERTSTR(!beamFormerStations.empty(), "No stations left to beam form! Aborting."); - - // Sort stations (CS, RS, int'l), to get a consistent and predictable order. - std::sort(beamFormerStations.begin(), beamFormerStations.end(), compareStationNames); - - settings.beamFormer.antennaFieldNames = ObservationSettings::expandAntennaFieldNames(beamFormerStations, settings.antennaSet); + settings.beamFormer.antennaFieldNames = getOutputTypeAntennaFieldNames("Cobalt.BeamFormer.stationList", stations); LOG_DEBUG_STR("Beamforming " << settings.beamFormer.antennaFieldNames.size() << " fields: " << settings.beamFormer.antennaFieldNames); ObservationSettings::BeamFormer::StokesSettings @@ -902,6 +875,113 @@ namespace LOFAR settings.beamFormer.dedispersionFFTsize = getUint32("Cobalt.BeamFormer.dedispersionFFTsize", settings.blockSize); } + /* =============================== + * RSPRaw collection information + * =============================== + */ + + settings.rspRaw.enabled = getBool("Observation.DataProducts.Output_RSPRaw.enabled", false); + if (settings.rspRaw.enabled) { + if (isDefined("Cobalt.RSPRaw.startTime")) { + settings.rspRaw.startTime = getTime("Cobalt.RSPRaw.startTime", ""); + } else { + settings.rspRaw.startTime = (time_t)settings.startTime; + } + if (isDefined("Cobalt.RSPRaw.stopTime")) { + settings.rspRaw.stopTime = getTime("Cobalt.RSPRaw.stopTime", ""); + } else { + settings.rspRaw.stopTime = (time_t)settings.stopTime; + } + + // Read antenna field names (via stationList key) to use for RSP raw output + settings.rspRaw.antennaFieldNames = getOutputTypeAntennaFieldNames("Cobalt.RSPRaw.stationList", stations); + if (settings.rspRaw.antennaFieldNames.empty()) { + settings.rspRaw.antennaFieldNames = settings.antennaFieldNames; // default + } + LOG_INFO_STR("RSP raw: " << settings.rspRaw.antennaFieldNames.size() << " fields: " << settings.rspRaw.antennaFieldNames); + + /* + * RSPRaw is not a supported output type in the rest of the system (it is COBALT-only). + * The Observatory specifies a correlation or beamforming observation, then copies a + * parset override in place. Hence, all RSPRaw settings must be auto-detectable (sane defaults), + * possibly from correlation or beamforming settings, even if those are not enabled (anymore)! + */ + vector<ObservationSettings::FileLocation> locations = getFileLocations("RSPRaw"); + const bool locationsAutoDetected = locations.empty(); + if (locationsAutoDetected) { + const vector<ObservationSettings::FileLocation> correlated_locations = getFileLocations("Correlated"); + const vector<ObservationSettings::FileLocation> coherent_locations = getFileLocations("CoherentStokes"); + const vector<ObservationSettings::FileLocation> incoherent_locations = getFileLocations("IncoherentStokes"); + + locations.insert(locations.end(), correlated_locations.begin(), correlated_locations.end()); + locations.insert(locations.end(), coherent_locations.begin(), coherent_locations.end()); + locations.insert(locations.end(), incoherent_locations.begin(), incoherent_locations.end()); + if (locations.empty()) { + THROW(CoInterfaceException, "No RSP raw locations specified and could not derive any location(s) from correlated, coherent, or incoherent file locations (even if not enabled)."); + } + + // Purge duplicate hostname locations. Clearing filenames first makes this easier. + for (size_t i = 0; i < locations.size(); ++i) { + locations[i].filename.clear(); + } + std::sort(locations.begin(), locations.end()); + std::unique(locations.begin(), locations.end()); + } + + // Assign output file locations + unsigned maxNrAntFieldStreams = 0; // normally we have 4 sending RSP boards per antenna field + unsigned locationIdx = 0; + for (size_t i = 0; i < settings.rspRaw.antennaFieldNames.size(); ++i) { + const ObservationSettings::AntennaFieldName& afName = settings.rspRaw.antennaFieldNames[i]; + vector<ObservationSettings::AntennaFieldName>::iterator nameIt = std::find(settings.antennaFieldNames.begin(), + settings.antennaFieldNames.end(), afName); + ASSERTSTR(nameIt == settings.antennaFieldNames.end(), "RSP raw antenna field name " << afName.fullName() << + " missing in observation antenna field list"); // getOutputTypeAntennaFieldNames() must have avoided this + vector<ObservationSettings::AntennaField>::iterator afIt = settings.antennaFields.begin() + + std::distance(settings.antennaFieldNames.begin(), nameIt); + size_t nrStreams = afIt->inputStreams.size(); + if (maxNrAntFieldStreams < nrStreams) { + maxNrAntFieldStreams = nrStreams; + } + + for (unsigned s = 0; s < nrStreams; ++s) { + if (locationIdx >= locations.size()) { + if (locationsAutoDetected) { + locationIdx = 0; // if auto-detected, assign locations in round-robin order + } else { // Either you specify no locations and we do it all, or you specify a complete list. No half-baked RSP raw settings! + THROW(CoInterfaceException, "No RSP raw filename or location specified for antenna field " << + afName.fullName() << " stream " << s); + } + } + + ObservationSettings::RSPRaw::File file; + file.antennaFieldNameIdx = i; + file.streamNr = s; + locations[locationIdx].filename = str(format("L%u_%s_%u_rsp.raw") % settings.observationID % afName.fullName().c_str() % s); + file.location = locations[locationIdx]; + settings.rspRaw.files.push_back(file); + + outputProcHosts.insert(file.location.host); + + locationIdx += 1; + } + } + + // Read nrBeamletsPerBoardList and apply sane defaults + settings.rspRaw.nrBeamletsPerBoardList = getUint32Vector("Cobalt.RSPRaw.nrBeamletsPerBoardList", + emptyVectorUnsigned, true); + if (settings.rspRaw.nrBeamletsPerBoardList.size() < maxNrAntFieldStreams) { + settings.rspRaw.nrBeamletsPerBoardList.resize(maxNrAntFieldStreams); + } + const unsigned maxNrPayloadBeamlets = 61 * 16 / settings.nrBitsPerSample; // see InputProc/src/Station/RSP.h, which we don't want to depend on here (better move hardware specs to CoInterface or LCS) + for (size_t i = 0; i < settings.rspRaw.nrBeamletsPerBoardList.size(); ++i) { + if (settings.rspRaw.nrBeamletsPerBoardList[i] > maxNrPayloadBeamlets) { + settings.rspRaw.nrBeamletsPerBoardList[i] = maxNrPayloadBeamlets; + } + } + } + + // set output hosts settings.outputProcHosts.clear(); for (set<string>::const_iterator i = outputProcHosts.begin(); i != outputProcHosts.end(); ++i) { @@ -915,6 +995,41 @@ namespace LOFAR return settings; } + vector<struct ObservationSettings::AntennaFieldName> + Parset::getOutputTypeAntennaFieldNames(const string& stationListKey, + const vector<string>& stations) const + { + vector<string> newStations = getStringVector(stationListKey, vector<string>(), true); + if (newStations.empty()) { + // if [], default to all stations + newStations = stations; + } else { + // filter out stations not in the observation. This allows basic defaults ([CS002..7] etc) to be used, even if + // they contain stations that are not available. + vector<string> filteredList; + + for (size_t i = 0; i < newStations.size(); i++) { + if (std::find(stations.begin(), stations.end(), + newStations[i]) != stations.end()) { + filteredList.push_back(newStations[i]); + } else { + LOG_WARN_STR("Removing station " << newStations[i] << " from interpreted " << stationListKey << + ", as it is not participating in the observation: " << settings.rawStationList); + } + } + + newStations = filteredList; + } + + // Note that this could happen by accident if too many stations are taken out of the observation, leaving none + ASSERTSTR(!newStations.empty(), "No stations left! Aborting."); + + // Sort stations (CS, RS, int'l), to get a consistent and predictable order. + std::sort(newStations.begin(), newStations.end(), compareStationNames); + + return ObservationSettings::expandAntennaFieldNames(newStations, settings.antennaSet); + } + bool Parset::nodeReadsAntennaFieldData(const struct ObservationSettings& settings, const string& nodeName) const { for (size_t i = 0; i < settings.antennaFields.size(); ++i) { @@ -1156,15 +1271,6 @@ namespace LOFAR } - void Parset::checkVectorLength(const std::string &key, unsigned expectedSize) const - { - unsigned actualSize = getStringVector(key, true).size(); - - if (actualSize != expectedSize) - THROW(CoInterfaceException, "Key \"" << string(key) << "\" contains wrong number of entries (expected: " << expectedSize << ", actual: " << actualSize << ')'); - } - - void Parset::checkInputConsistency() const { } @@ -1185,10 +1291,13 @@ namespace LOFAR std::string Parset::getHostName(OutputType outputType, unsigned streamNr) const { if (outputType == CORRELATED_DATA) - return settings.correlator.files[streamNr].location.host; + return settings.correlator.files.at(streamNr).location.host; if (outputType == BEAM_FORMED_DATA) - return settings.beamFormer.files[streamNr].location.host; + return settings.beamFormer.files.at(streamNr).location.host; + + if (outputType == RSP_RAW_DATA) + return settings.rspRaw.files.at(streamNr).location.host; return "unknown"; } @@ -1197,10 +1306,13 @@ namespace LOFAR std::string Parset::getFileName(OutputType outputType, unsigned streamNr) const { if (outputType == CORRELATED_DATA) - return settings.correlator.files[streamNr].location.filename; + return settings.correlator.files.at(streamNr).location.filename; if (outputType == BEAM_FORMED_DATA) - return settings.beamFormer.files[streamNr].location.filename; + return settings.beamFormer.files.at(streamNr).location.filename; + + if (outputType == RSP_RAW_DATA) + return settings.rspRaw.files.at(streamNr).location.filename; return "unknown"; } @@ -1209,10 +1321,13 @@ namespace LOFAR std::string Parset::getDirectoryName(OutputType outputType, unsigned streamNr) const { if (outputType == CORRELATED_DATA) - return settings.correlator.files[streamNr].location.directory; + return settings.correlator.files.at(streamNr).location.directory; if (outputType == BEAM_FORMED_DATA) - return settings.beamFormer.files[streamNr].location.directory; + return settings.beamFormer.files.at(streamNr).location.directory; + + if (outputType == RSP_RAW_DATA) + return settings.rspRaw.files.at(streamNr).location.directory; return "unknown"; } @@ -1226,10 +1341,26 @@ namespace LOFAR switch (outputType) { case CORRELATED_DATA: return settings.correlator.files.size(); case BEAM_FORMED_DATA: return settings.beamFormer.files.size(); + case RSP_RAW_DATA: return settings.rspRaw.files.size(); default: THROW(CoInterfaceException, "Unknown output type"); } } + unsigned Parset::getRSPRawOutputStreamIdx(const std::string& antennaFieldName, + unsigned boardNr) const + { + const std::vector<ObservationSettings::RSPRaw::File>& files = settings.rspRaw.files; + for (size_t i = 0; i < files.size(); ++i) { + if (settings.rspRaw.antennaFieldNames.at(files[i].antennaFieldNameIdx).fullName() == antennaFieldName && + files[i].streamNr == boardNr) { + return i; + } + } + + THROW(CoInterfaceException, "Unknown output stream for antenna field name " << + antennaFieldName << " and RSP board nr " << boardNr); + } + size_t Parset::nrBytesPerComplexSample() const { return 2 * nrBitsPerSample() / 8; @@ -1300,7 +1431,7 @@ namespace LOFAR return list; } - double Parset::getTime(const std::string &name, const std::string &defaultValue) const + time_t Parset::getTime(const std::string &name, const std::string &defaultValue) const { return LOFAR::to_time_t(boost::posix_time::time_from_string(getString(name, defaultValue))); } @@ -1372,7 +1503,7 @@ namespace LOFAR return settings.nrBitsPerSample; } - unsigned Parset::nrObsOutputTypes() const + unsigned Parset::nrProcessedOutputTypes() const { unsigned nr = 0; @@ -1385,6 +1516,7 @@ namespace LOFAR if (settings.beamFormer.anyIncoherentTABs()) { nr += 1; } + // RSP raw is not a processed output type, so not counted: see caller(s) for impact if changing this return nr; } @@ -1394,6 +1526,7 @@ namespace LOFAR switch (outputType) { case CORRELATED_DATA: return settings.correlator.enabled; case BEAM_FORMED_DATA: return settings.beamFormer.enabled; + case RSP_RAW_DATA: return settings.rspRaw.enabled; default: THROW(CoInterfaceException, "Unknown output type"); } } diff --git a/RTCP/Cobalt/CoInterface/src/Parset.h b/RTCP/Cobalt/CoInterface/src/Parset.h index 9686bf00f34..7c9066f02c9 100644 --- a/RTCP/Cobalt/CoInterface/src/Parset.h +++ b/RTCP/Cobalt/CoInterface/src/Parset.h @@ -1,5 +1,5 @@ //# Parset.h: class/struct that holds the Parset information -//# Copyright (C) 2008-2015 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2008-2017 ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -191,8 +191,13 @@ namespace LOFAR antennaField == other.antennaField; } + bool operator==(const std::string &other) const { + return fullName() == other; + } + // Returns the indices in fullSet for each element of subSet. - static std::vector<unsigned> indices(const std::vector<AntennaFieldName> &subSet, const std::vector<AntennaFieldName> &fullSet); + static std::vector<unsigned> indices(const std::vector<AntennaFieldName> &subSet, + const std::vector<AntennaFieldName> &fullSet); // Returns a list of the station names. static std::vector<std::string> names( const std::vector<AntennaFieldName> &list ); @@ -290,8 +295,8 @@ namespace LOFAR // Host name std::string hostName; - // CPU number to bind to - size_t cpu; + // CPU socket number to bind to, or -1 to not bind to any + int cpu; // CUDA GPU numbers to bind to std::vector<unsigned> gpus; @@ -306,6 +311,7 @@ namespace LOFAR std::vector<struct Node> nodes; // Cluster where data writers run + // TODO: move to per output type and read Output_XXX.storageClusterName keys std::string outputCluster; /* @@ -408,6 +414,28 @@ namespace LOFAR string host; string directory; string filename; + + // Make FileLocation objects comparable and equality testable, + // so we can prune dups in a vector using sort + unique. + bool operator<(const FileLocation& rhs) const { + int cmp = cluster.compare(rhs.cluster); + if (cmp < 0) return true; + if (cmp > 0) return false; + cmp = host.compare(rhs.host); + if (cmp < 0) return true; + if (cmp > 0) return false; + cmp = directory.compare(rhs.directory); + if (cmp < 0) return true; + if (cmp > 0) return false; + cmp = filename.compare(rhs.filename); + if (cmp < 0) return true; + return false; + } + + bool operator==(const FileLocation& rhs) const { + return filename == rhs.filename && host == rhs.host && + directory == rhs.directory && cluster == rhs.cluster; + } }; /* =============================== @@ -583,6 +611,9 @@ namespace LOFAR // Antenna fields to use for beam forming. // Must be a subset of the observation antenna-field list + // + // Derived from key: Cobalt.Beamformer.stationList + // TODO: split up in CoherentStokes and IncoherentStokes antenna field name lists std::vector<AntennaFieldName> antennaFieldNames; // All SAPs, with information about the TABs to form. @@ -654,6 +685,64 @@ namespace LOFAR struct BeamFormer beamFormer; + /* =============================== + * RSPRaw collection information + * =============================== + */ + + struct RSPRaw { + // Whether RSP raw data collection was requested. + // + // key: Observation.DataProducts.Output_RSPRaw.enabled + // Default: false + bool enabled; + + // Specified RSP raw data dump / piggy backing start time (inclusive) + // in seconds since 1970. + // + // key: Cobalt.RSPRaw.startTime + // Default: value of Observation.startTime + time_t startTime; + + // Specified raw RSP data dump / piggy backing stop time (exclusive) + // in seconds since 1970. + // + // key: Cobalt.RSPRaw.stopTime + // Default: value of Observation.stopTime + time_t stopTime; + + // All antenna fields specified for RSP raw output + // Must be a subset of the observation antenna-field list + // + // Derived from key: Cobalt.RSPRaw.stationList + // Default value: antennaFieldNames (observation wide) + std::vector<AntennaFieldName> antennaFieldNames; + + // A vector with per RSP board (for all stations) the number of beamlets, + // to send out from each station RSP frame. + // Vector size must be the (max) number of antenna field input streams (typically 4). + // (This is a cheap variant of full (beam, subband) selection per (station, board).) + // + // key: Cobalt.RSPRaw.nrBeamletsPerBoardList + // An absent key, missing values (vector too small), or too high value means all. + std::vector<unsigned> nrBeamletsPerBoardList; + + struct File { + // Index into *RSP raw* antennaFieldNames + unsigned antennaFieldNameIdx; + + // Stream number, aka sender RSP board nr (typically 0-3) + unsigned streamNr; + + struct FileLocation location; + }; + + // The list of files to write + std::vector<struct File> files; + }; + + struct RSPRaw rspRaw; + // Returns the Nyquist zone number based on bandFilter. unsigned nyquistZone() const; @@ -710,13 +799,14 @@ namespace LOFAR std::string positionType() const; unsigned dedispersionFFTsize() const; - unsigned nrObsOutputTypes() const; + unsigned nrProcessedOutputTypes() const; bool outputThisType(OutputType) const; unsigned nrStreams(OutputType, bool force = false) const; std::string getHostName(OutputType, unsigned streamNr) const; std::string getFileName(OutputType, unsigned streamNr) const; std::string getDirectoryName(OutputType, unsigned streamNr) const; + unsigned getRSPRawOutputStreamIdx(const std::string& antennaFieldName, unsigned boardNr) const; double channel0Frequency( size_t subband, size_t nrChannels ) const; @@ -729,14 +819,17 @@ namespace LOFAR mutable std::string itsWriteCache; - void checkVectorLength(const std::string &key, unsigned expectedSize) const; void checkInputConsistency() const; void addPosition(string stName); - double getTime(const std::string &name, const std::string &defaultValue) const; + time_t getTime(const std::string &name, const std::string &defaultValue) const; std::vector<double> centroidPos(const string &stations) const; + std::vector<struct ObservationSettings::AntennaFieldName> + getOutputTypeAntennaFieldNames(const std::string& stationListKey, + const std::vector<std::string>& stations) const; + std::vector<struct ObservationSettings::FileLocation> getFileLocations(const std::string outputType) const; // Returns whether nodeName has to participate in the observation diff --git a/RTCP/Cobalt/InputProc/src/Station/RSP.h b/RTCP/Cobalt/CoInterface/src/RSP.h similarity index 91% rename from RTCP/Cobalt/InputProc/src/Station/RSP.h rename to RTCP/Cobalt/CoInterface/src/RSP.h index ef602ae268d..1f3ca85708f 100644 --- a/RTCP/Cobalt/InputProc/src/Station/RSP.h +++ b/RTCP/Cobalt/CoInterface/src/RSP.h @@ -1,5 +1,6 @@ //# RSP.h: RSP data format -//# Copyright (C) 2012-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2012-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -18,8 +19,8 @@ //# //# $Id$ -#ifndef LOFAR_INPUT_PROC_RSP_H -#define LOFAR_INPUT_PROC_RSP_H +#ifndef LOFAR_INTERFACE_RSP_H +#define LOFAR_INTERFACE_RSP_H #include <cstddef> #include <complex> @@ -51,7 +52,7 @@ namespace LOFAR // ---------------------------------------------------------------------- struct Header { - // 2: Beamlet Data CoInterface 5.0 + // 2: Beamlet Data CoInterface 5.0: no longer supported // 3: Beamlet Data CoInterface 6.0 (8- and 4-bit mode support) uint8 version; @@ -98,7 +99,8 @@ namespace LOFAR // Payload, allocated for maximum size. // Actual size depends on the header (nrBeamlets, nrBlocks). It changed in - // the past (61 vs 60) and may be less for tests and old pre-recorded data + // the past (61 vs 60) and may be less for tests, old pre-recorded data, and + // RSP raw output for offline reprocessing or piggy-backing (selectable beamlet subset). union Payload { char data[8130]; @@ -167,15 +169,9 @@ namespace LOFAR unsigned bitMode() const { - if (header.version < 3) - return 16; - - switch (header.sourceInfo2 & 0x3) { - default: - case 0x0: return 16; - case 0x1: return 8; - case 0x2: return 4; - } + //if (header.version < 3) // disabled: Beamlet Data CoInterface 5.0 is too old to care and in a hot path + // return 16; + return 16 >> header.sourceInfo2; // 0x0: 16, 0x1: 8, 0x2: 4 } void bitMode(unsigned mode) @@ -206,6 +202,11 @@ namespace LOFAR header.blockSequenceNumber = ts.getBlockId(); } + void timeStampError() + { + header.timestamp = 0xFFFFFFFF; // clock not initialised + } + size_t packetSize() const { return sizeof(RSP::Header) + header.nrBlocks * header.nrBeamlets * 2 * 2 * bitMode() / 8; diff --git a/RTCP/Cobalt/CoInterface/src/RSPRawTransfer.cc b/RTCP/Cobalt/CoInterface/src/RSPRawTransfer.cc new file mode 100644 index 00000000000..7d6e35e37f8 --- /dev/null +++ b/RTCP/Cobalt/CoInterface/src/RSPRawTransfer.cc @@ -0,0 +1,207 @@ +//# RSPRawTransfer.cc: Sender and receiver for RSP raw output +//# Copyright (C) 2017 ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> + +#include "RSPRawTransfer.h" + +#include <cstring> +#include <fcntl.h> +#include <sys/socket.h> +#include <Common/LofarLogger.h> +#include <Common/SystemCallException.h> +#include <Stream/StreamFactory.h> + +using namespace std; + +namespace LOFAR { + namespace Cobalt { + + /* RSPRawSender */ + + RSPRawSender::RSPRawSender() : + itsStream(NULL), + itsSentMsgSizes(0), + itsNrBeamletsToSend(0), + itsNrDroppedPackets(0) + { + } + + RSPRawSender::RSPRawSender(unsigned maxNrPacketsPerSend, unsigned nrBeamletsToSend, + const string& streamDesc, time_t deadline) : + itsStream(createStream(streamDesc, false, deadline)), + itsSentMsgSizes(maxNrPacketsPerSend), + itsNrBeamletsToSend(nrBeamletsToSend), + itsNrDroppedPackets(0) + { + ASSERTSTR(maxNrPacketsPerSend > 0, "maxNrPacketsPerSend must be > 0"); + + // In RT mode InputProc threads may not block. Prefer not sent (i.e. dropped) packets. + if (deadline != 0) { + FileDescriptorBasedStream *fdStream = dynamic_cast<FileDescriptorBasedStream *>(itsStream.get()); + if (fdStream != NULL) { + fdStream->fcntl(F_SETFL, fdStream->fcntl(F_GETFL) | O_NONBLOCK); + } + } + } + + RSPRawSender::~RSPRawSender() + { + try { + trySendPending(); // try, but it may be way too late + } catch (SystemCallException& ) { + itsNrDroppedPackets += 1; // count partially sent as dropped now + } + + if (itsNrDroppedPackets > 0) { + SocketStream *sockStream = dynamic_cast<SocketStream *>(itsStream.get()); + if (sockStream == NULL) { + LOG_WARN_STR("RSPRawSender: number of RSP packets not sent: " << itsNrDroppedPackets); + } else { + LOG_WARN_STR("RSPRawSender " << sockStream->getHostname() << ':' << sockStream->getPort() << + " number of RSP packets not sent: " << itsNrDroppedPackets); + } + } + } + + bool RSPRawSender::initialized() const + { + return itsStream != NULL; + } + + unsigned RSPRawSender::getNrDroppedPackets() const + { + return itsNrDroppedPackets; + } + + void RSPRawSender::trySend(struct RSP *packets, unsigned nrPackets) + { + ASSERTSTR(nrPackets <= itsSentMsgSizes.size(), "nrPackets > max indicated when sender was constructed"); + + /* + * Patch packet headers if we need to send only the 1st N beamlets. + * Note: we assume all packets (per RSP board) have the same nrBeamlets and size. + * If not in nrBeamlets, we may incorrectly restore some of the packet headers below... + * If not in size, we may append bogus (or uninit data), but struct RSP is large enough. + */ + const uint8 packetNrBeamlets = packets[0].header.nrBeamlets; // save to restore + if (itsNrBeamletsToSend < packetNrBeamlets) { + for (unsigned i = 0; i < nrPackets; i++) { + packets[i].header.nrBeamlets = itsNrBeamletsToSend; + } + } + + size_t packetSize = packets[0].packetSize(); + SocketStream *sockStream = dynamic_cast<SocketStream *>(itsStream.get()); + try { + if (sockStream != NULL && sockStream->protocol == SocketStream::UDP) { + /* + * MSG_CONFIRM: Inform link-layer to just send the data without periodic ARP probing. + * We haven't seen any replies (network peer doesn't send any in this case, with its downsides), + * but we cannot afford stalls. + */ + unsigned nrSent = sockStream->sendmmsg(packets, packetSize, itsSentMsgSizes, MSG_CONFIRM); + if (nrSent < nrPackets) { // don't check itsSentMsgSizes: resending remainders won't help with UDP (message oriented) + itsNrDroppedPackets += nrPackets - nrSent; + LOG_WARN("RSPRawSender::trySend(): fewer sent to avoid blocking"); // not retried, not even in non-RT... + } + } else { // no SocketStream or SocketStream::TCP + // With TCP we must avoid partial RSP frame transfer. Try sending any remaining data of 1 RSP packet first. + trySendPending(); // may throw + + // Prepare writev(2) + vector<struct iovec> iov(nrPackets); + for (unsigned i = 0; i < nrPackets; i++) { + iov[i].iov_base = (char *)packets + i * packetSize; + iov[i].iov_len = packetSize; + } + + size_t bytesSent = itsStream->tryWritev(&iov[0], nrPackets); // may throw + if (bytesSent < nrPackets * packetSize) { + // Drop, except for unsent data of partially sent packet (if so). Stash that to retry later. + unsigned nrSent = bytesSent / packetSize; + unsigned partialPacketSent = bytesSent % packetSize; + if (partialPacketSent != 0) { + LOG_WARN("RSPRawSender::trySend(): partial packet sent: will retry remainder later"); + const char *data = (char *)iov[nrSent].iov_base + partialPacketSent; + size_t size = packetSize - partialPacketSent; + itsPendingData.resize(size); + std::memcpy(&itsPendingData[0], data, size); + nrSent += 1; // partially sent and stashed + } + + itsNrDroppedPackets += nrPackets - nrSent; + LOG_WARN("RSPRawSender::trySend(): fewer sent to avoid blocking"); // not retried, not even in non-RT... + } + } + } catch (SystemCallException& exc) { + itsNrDroppedPackets += nrPackets; + if (exc.error == EAGAIN || exc.error == EWOULDBLOCK) { + LOG_WARN("RSPRawSender: sent fewer packets than requested to avoid blocking"); + } else { + static bool errorSeen; + if (!errorSeen) { + LOG_ERROR_STR("RSPRawSender: " << exc.what()); // backtrace not useful here + errorSeen = true; + } + } + } + + if (itsNrBeamletsToSend < packetNrBeamlets) { + for (unsigned i = 0; i < nrPackets; i++) { + packets[i].header.nrBeamlets = packetNrBeamlets; // restore + } + } + } + + void RSPRawSender::trySendPending() + { + if (!itsPendingData.empty()) { + size_t bytesSent = itsStream->tryWrite(&itsPendingData[0], itsPendingData.size()); // may throw + size_t newSize = itsPendingData.size() - bytesSent; + std::memmove(&itsPendingData[0], &itsPendingData[bytesSent], newSize); // at most 8k + itsPendingData.resize(newSize); + } + } + + + /* RSPRawReceiver */ + + RSPRawReceiver::RSPRawReceiver() : + itsStream(NULL) + { + } + + RSPRawReceiver::RSPRawReceiver(const string& streamDesc) : + itsStream(createStream(streamDesc, true)) + { + } + + RSPRawReceiver::~RSPRawReceiver() + { + } + + void RSPRawReceiver::receive() const + { + } + + } // namespace Cobalt +} // namespace LOFAR + diff --git a/RTCP/Cobalt/CoInterface/src/RSPRawTransfer.h b/RTCP/Cobalt/CoInterface/src/RSPRawTransfer.h new file mode 100644 index 00000000000..34c117cefbd --- /dev/null +++ b/RTCP/Cobalt/CoInterface/src/RSPRawTransfer.h @@ -0,0 +1,84 @@ +//# RSPRawTransfer.h: Sender and receiver for RSP raw output +//# Copyright (C) 2017 ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_COINTERFACE_RSPRAWTRANSFER_H +#define LOFAR_COINTERFACE_RSPRAWTRANSFER_H + +// \file +// Sender and receiver for RSP raw output. Sender is also used for COBALT RSP data piggy-backing. + +#include <ctime> // time_t +#include <string> +#include <Stream/SocketStream.h> +#include "RSP.h" +#include "SmartPtr.h" + +namespace LOFAR +{ + namespace Cobalt + { + +class RSPRawSender { +public: + RSPRawSender(); + + // deadline is an absolute timestamp or 0 for no connection timeout (blocking). + RSPRawSender(unsigned maxNrPacketsPerSend, unsigned nrBeamletsToSend, + const std::string& streamDesc, time_t deadline = 0); + + ~RSPRawSender(); + + bool initialized() const; + + // Ensure nrPackets <= maxNrPacketsPerSend (passed upon object construction). + // If deadline (passed upon object construction) was non-zero, trySend() may drop packets to avoid blocking. + void trySend(struct RSP *packets, unsigned nrPackets); + + unsigned getNrDroppedPackets() const; + +private: + void trySendPending(); + + SmartPtr<Stream> itsStream; + std::vector<unsigned> itsSentMsgSizes; + unsigned itsNrBeamletsToSend; + unsigned itsNrDroppedPackets; + std::vector<unsigned char> itsPendingData; // w/ TCP to retry sending the remainder of a partially sent RSP packet +}; + +class RSPRawReceiver { +public: + RSPRawReceiver(); + + RSPRawReceiver(const std::string& streamDesc); + + ~RSPRawReceiver(); + + void receive() const; + +private: + SmartPtr<Stream> itsStream; +}; + + } // namespace Cobalt +} // namespace LOFAR + +#endif + diff --git a/RTCP/Cobalt/CoInterface/src/Stream.cc b/RTCP/Cobalt/CoInterface/src/Stream.cc index 24d4a3385f2..f83c8bae797 100644 --- a/RTCP/Cobalt/CoInterface/src/Stream.cc +++ b/RTCP/Cobalt/CoInterface/src/Stream.cc @@ -61,6 +61,7 @@ namespace LOFAR // The returned descriptor can be supplied to LCS/Stream StreamFactory.h + // For RSP raw impl convenience this function must remain thread-safe. string getStreamDescriptorBetweenIONandStorage(const Parset &parset, OutputType outputType, unsigned streamNr, const std::string &bind_local_iface) { string host = parset.getHostName(outputType, streamNr); diff --git a/RTCP/Cobalt/CoInterface/src/StreamableData.h b/RTCP/Cobalt/CoInterface/src/StreamableData.h index 5fe7ec3e223..0237ecd0b08 100644 --- a/RTCP/Cobalt/CoInterface/src/StreamableData.h +++ b/RTCP/Cobalt/CoInterface/src/StreamableData.h @@ -1,5 +1,6 @@ //# StreamableData.h -//# Copyright (C) 2008-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2008-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -25,11 +26,12 @@ #include <Common/LofarTypes.h> #include <Common/DataConvert.h> -#include <CoInterface/Parset.h> -#include <CoInterface/MultiDimArray.h> -#include <CoInterface/SparseSet.h> -#include <CoInterface/Allocator.h> #include <Stream/Stream.h> +#include "Parset.h" +#include "MultiDimArray.h" +#include "SparseSet.h" +#include "Allocator.h" +#include "RSP.h" namespace LOFAR { @@ -50,15 +52,20 @@ namespace LOFAR // the CPU which fills the datastructure sets the peerMagicNumber, // because other CPUs will overwrite it with a read(s,true) call from // either disk or network. - StreamableData() : peerMagicNumber(magic), rawSequenceNumber(0) + StreamableData(bool readWithSeqNr = true, bool writeWithSeqNr = true) + : peerMagicNumber(magic), + readWithSequenceNumber(readWithSeqNr), + writeWithSequenceNumber(writeWithSeqNr), + rawSequenceNumber(0) { } + virtual ~StreamableData() { } - void read(Stream *, bool withSequenceNumber, unsigned align = 1); - void write(Stream *, bool withSequenceNumber, unsigned align = 1); + void read(Stream *, unsigned align); + void write(Stream *, unsigned align); bool shouldByteSwap() const { @@ -98,6 +105,8 @@ namespace LOFAR virtual void writeData(Stream *, unsigned) = 0; private: + bool readWithSequenceNumber; + bool writeWithSequenceNumber; uint32_t rawSequenceNumber; /// possibly needs byte swapping }; @@ -121,9 +130,9 @@ namespace LOFAR }; - inline void StreamableData::read(Stream *str, bool withSequenceNumber, unsigned alignment) + inline void StreamableData::read(Stream *str, unsigned alignment) { - if (withSequenceNumber) { + if (readWithSequenceNumber) { std::vector<char> header(alignment > 2 * sizeof(uint32_t) ? alignment : 2 * sizeof(uint32_t)); uint32_t &magicValue = *reinterpret_cast<uint32_t *>(&header[0]); uint32_t &seqNo = *reinterpret_cast<uint32_t *>(&header[sizeof(uint32_t)]); @@ -138,10 +147,10 @@ namespace LOFAR } - inline void StreamableData::write(Stream *str, bool withSequenceNumber, unsigned alignment) + inline void StreamableData::write(Stream *str, unsigned alignment) { - if (withSequenceNumber) { + if (writeWithSequenceNumber) { /* std::vector<char> header(alignment > sizeof(uint32_t) ? alignment : sizeof(uint32_t)); */ std::vector<char> header(alignment > 2 * sizeof(uint32_t) ? alignment : 2 * sizeof(uint32_t)); uint32_t &magicValue = *reinterpret_cast<uint32_t *>(&header[0]); @@ -187,6 +196,40 @@ namespace LOFAR str->write(samples.origin(), samples.num_elements() * sizeof(T)); } + + class RSPRawData : public StreamableData + { + public: + RSPRawData() + : StreamableData(false, false), // raw: no seq nrs + buffer(bufferSize), + used(0) + { + } + + protected: + virtual void readData(Stream *str, unsigned alignment) + { + (void)alignment; + + used = str->tryRead(&buffer[0], bufferSize); // don't know what to expect, so read what is avail + } + + virtual void writeData(Stream *str, unsigned alignment) + { + (void)alignment; + + str->write(&buffer[0], used); + used = 0; + } + + private: + static const unsigned bufferSize = 64 * sizeof(RSP); + + vector<uint8_t> buffer; // vector<RSP> could have worked, but byte stream from TCP to storage + size_t used; + }; + } // namespace Cobalt } // namespace LOFAR diff --git a/RTCP/Cobalt/CoInterface/test/CMakeLists.txt b/RTCP/Cobalt/CoInterface/test/CMakeLists.txt index 007b8b7c288..d5f8b1bba3c 100644 --- a/RTCP/Cobalt/CoInterface/test/CMakeLists.txt +++ b/RTCP/Cobalt/CoInterface/test/CMakeLists.txt @@ -11,6 +11,7 @@ lofar_add_test(tpow2 tpow2.cc) lofar_add_test(tSparseSet tSparseSet.cc) lofar_add_test(tfpequals tfpequals.cc) lofar_add_test(tcmpfloat DEPENDS cmpfloat) +lofar_add_test(tRSPRawTransfer tRSPRawTransfer.cc) if(UNITTEST++_FOUND) diff --git a/RTCP/Cobalt/CoInterface/test/tRSPRawTransfer.cc b/RTCP/Cobalt/CoInterface/test/tRSPRawTransfer.cc new file mode 100644 index 00000000000..aaebc93c793 --- /dev/null +++ b/RTCP/Cobalt/CoInterface/test/tRSPRawTransfer.cc @@ -0,0 +1,76 @@ +//# tRSPRawTransfer.cc +//# Copyright (C) 2017 ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> + +#include <omp.h> + +#include <Common/LofarLogger.h> +#include <CoInterface/RSPRawTransfer.h> + +using namespace LOFAR; +using namespace LOFAR::Cobalt; +using namespace std; + +static bool doSender(void) +{ +//TODO RSPRawSender sender(...); + + return true; +} + +static bool doReceiver(void) +{ +//TODO RSPRawReceiver receiver(...); + + return true; +} + +static bool runTest(void) +{ + bool senderStatus; + bool receiverStatus; + + // create sender and receiver in separate threads for easy testing +# pragma omp parallel sections num_threads(2) + { +# pragma omp section + { + senderStatus = doSender(); + } + +# pragma omp section + { + receiverStatus = doReceiver(); + } + } + + return senderStatus && receiverStatus; +} + +int main(void) +{ + INIT_LOGGER("tRSPRawTransfer"); + + bool status = runTest(); + + return !status; +} + diff --git a/RTCP/Cobalt/GPUProc/etc/CMakeLists.txt b/RTCP/Cobalt/GPUProc/etc/CMakeLists.txt index aca4d465e8a..f43abc09e42 100644 --- a/RTCP/Cobalt/GPUProc/etc/CMakeLists.txt +++ b/RTCP/Cobalt/GPUProc/etc/CMakeLists.txt @@ -23,5 +23,9 @@ file(GLOB _config_parsets_bin "${CMAKE_CURRENT_BINARY_DIR}/parset-additions.d/de install(FILES ${_config_parsets_bin} DESTINATION etc/parset-additions.d/default) #lofar_add_sysconf_files(${_config_parsets_bin}) +# Enable RSP raw data output (and disable correlated and beamformed output) by copying this file into override/ replacing OBSID by the observation id. +install(DIRECTORY DESTINATION etc/parset-additions.d/override) # pre-create directory, because we tell users to copy into it +install(FILES "parset-additions.d/rspraw-enable.parset.OBSID" DESTINATION etc/parset-additions.d) + # Install script to generate StationStreams.parset for the live test system. lofar_add_sbin_scripts(parset-additions.d/default/generateStationStreams.sh) diff --git a/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareList.parset b/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareList.parset index f5ac9d995bb..2cb8d95630e 100644 --- a/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareList.parset +++ b/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareList.parset @@ -14,7 +14,7 @@ PIC.Core.Cobalt.localhost.gpus=[0] PIC.Core.Cobalt.gpu01_0.host=gpu01 PIC.Core.Cobalt.gpu01_0.cpu=0 PIC.Core.Cobalt.gpu01_0.mpi_nic= -PIC.Core.Cobalt.gpu01_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.gpu01_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.gpu01_0.gpus=[0, 1] PIC.Core.Cobalt.gpu01_1.host=gpu01 @@ -27,119 +27,260 @@ PIC.Core.Cobalt.gpu01_1.gpus=[2, 3] PIC.Core.Cobalt.cbt001_0.host=cbt001 PIC.Core.Cobalt.cbt001_0.cpu=0 PIC.Core.Cobalt.cbt001_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt001_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt001_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt001_0.gpus=[0, 1] PIC.Core.Cobalt.cbt001_1.host=cbt001 PIC.Core.Cobalt.cbt001_1.cpu=1 PIC.Core.Cobalt.cbt001_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt001_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt001_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt001_1.gpus=[2, 3] PIC.Core.Cobalt.cbt002_0.host=cbt002 PIC.Core.Cobalt.cbt002_0.cpu=0 PIC.Core.Cobalt.cbt002_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt002_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt002_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt002_0.gpus=[0, 1] PIC.Core.Cobalt.cbt002_1.host=cbt002 PIC.Core.Cobalt.cbt002_1.cpu=1 PIC.Core.Cobalt.cbt002_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt002_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt002_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt002_1.gpus=[2, 3] PIC.Core.Cobalt.cbt003_0.host=cbt003 PIC.Core.Cobalt.cbt003_0.cpu=0 PIC.Core.Cobalt.cbt003_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt003_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt003_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt003_0.gpus=[0, 1] PIC.Core.Cobalt.cbt003_1.host=cbt003 PIC.Core.Cobalt.cbt003_1.cpu=1 PIC.Core.Cobalt.cbt003_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt003_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt003_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt003_1.gpus=[2, 3] PIC.Core.Cobalt.cbt004_0.host=cbt004 PIC.Core.Cobalt.cbt004_0.cpu=0 PIC.Core.Cobalt.cbt004_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt004_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt004_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt004_0.gpus=[0, 1] PIC.Core.Cobalt.cbt004_1.host=cbt004 PIC.Core.Cobalt.cbt004_1.cpu=1 PIC.Core.Cobalt.cbt004_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt004_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt004_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt004_1.gpus=[2, 3] PIC.Core.Cobalt.cbt005_0.host=cbt005 PIC.Core.Cobalt.cbt005_0.cpu=0 PIC.Core.Cobalt.cbt005_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt005_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt005_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt005_0.gpus=[0, 1] PIC.Core.Cobalt.cbt005_1.host=cbt005 PIC.Core.Cobalt.cbt005_1.cpu=1 PIC.Core.Cobalt.cbt005_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt005_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt005_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt005_1.gpus=[2, 3] PIC.Core.Cobalt.cbt006_0.host=cbt006 PIC.Core.Cobalt.cbt006_0.cpu=0 PIC.Core.Cobalt.cbt006_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt006_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt006_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt006_0.gpus=[0, 1] PIC.Core.Cobalt.cbt006_1.host=cbt006 PIC.Core.Cobalt.cbt006_1.cpu=1 PIC.Core.Cobalt.cbt006_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt006_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt006_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt006_1.gpus=[2, 3] PIC.Core.Cobalt.cbt007_0.host=cbt007 PIC.Core.Cobalt.cbt007_0.cpu=0 PIC.Core.Cobalt.cbt007_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt007_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt007_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt007_0.gpus=[0, 1] PIC.Core.Cobalt.cbt007_1.host=cbt007 PIC.Core.Cobalt.cbt007_1.cpu=1 PIC.Core.Cobalt.cbt007_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt007_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt007_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt007_1.gpus=[2, 3] PIC.Core.Cobalt.cbt008_0.host=cbt008 PIC.Core.Cobalt.cbt008_0.cpu=0 PIC.Core.Cobalt.cbt008_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt008_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt008_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt008_0.gpus=[0, 1] PIC.Core.Cobalt.cbt008_1.host=cbt008 PIC.Core.Cobalt.cbt008_1.cpu=1 PIC.Core.Cobalt.cbt008_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt008_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt008_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt008_1.gpus=[2, 3] PIC.Core.Cobalt.cbt009_0.host=cbt009 PIC.Core.Cobalt.cbt009_0.cpu=0 PIC.Core.Cobalt.cbt009_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt009_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt009_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt009_0.gpus=[0, 1] PIC.Core.Cobalt.cbt009_1.host=cbt009 PIC.Core.Cobalt.cbt009_1.cpu=1 PIC.Core.Cobalt.cbt009_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt009_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt009_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt009_1.gpus=[2, 3] PIC.Core.Cobalt.cbt010_0.host=cbt010 PIC.Core.Cobalt.cbt010_0.cpu=0 PIC.Core.Cobalt.cbt010_0.mpi_nic=mlx4_0 -PIC.Core.Cobalt.cbt010_0.out_nic=[CEP4:ib0,DragNet:ib0] +PIC.Core.Cobalt.cbt010_0.out_nic=[CEP4:ib0,DRAGNET:ib0] PIC.Core.Cobalt.cbt010_0.gpus=[0, 1] PIC.Core.Cobalt.cbt010_1.host=cbt010 PIC.Core.Cobalt.cbt010_1.cpu=1 PIC.Core.Cobalt.cbt010_1.mpi_nic=mlx4_1 -PIC.Core.Cobalt.cbt010_1.out_nic=[CEP4:ib1,DragNet:ib1] +PIC.Core.Cobalt.cbt010_1.out_nic=[CEP4:ib1,DRAGNET:ib1] PIC.Core.Cobalt.cbt010_1.gpus=[2, 3] + +# The DRAGNET cluster (without dragnet head node and dragproc node) + +PIC.Core.DRAGNET.drg01.host=drg01 +PIC.Core.DRAGNET.drg01.cpu=-1 +PIC.Core.DRAGNET.drg01.mpi_nic= +PIC.Core.DRAGNET.drg01.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg01.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg02.host=drg02 +PIC.Core.DRAGNET.drg02.cpu=-1 +PIC.Core.DRAGNET.drg02.mpi_nic= +PIC.Core.DRAGNET.drg02.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg02.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg03.host=drg03 +PIC.Core.DRAGNET.drg03.cpu=-1 +PIC.Core.DRAGNET.drg03.mpi_nic= +PIC.Core.DRAGNET.drg03.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg03.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg04.host=drg04 +PIC.Core.DRAGNET.drg04.cpu=-1 +PIC.Core.DRAGNET.drg04.mpi_nic= +PIC.Core.DRAGNET.drg04.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg04.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg05.host=drg05 +PIC.Core.DRAGNET.drg05.cpu=-1 +PIC.Core.DRAGNET.drg05.mpi_nic= +PIC.Core.DRAGNET.drg05.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg05.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg06.host=drg06 +PIC.Core.DRAGNET.drg06.cpu=-1 +PIC.Core.DRAGNET.drg06.mpi_nic= +PIC.Core.DRAGNET.drg06.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg06.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg07.host=drg07 +PIC.Core.DRAGNET.drg07.cpu=-1 +PIC.Core.DRAGNET.drg07.mpi_nic= +PIC.Core.DRAGNET.drg07.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg07.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg08.host=drg08 +PIC.Core.DRAGNET.drg08.cpu=-1 +PIC.Core.DRAGNET.drg08.mpi_nic= +PIC.Core.DRAGNET.drg08.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg08.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg09.host=drg09 +PIC.Core.DRAGNET.drg09.cpu=-1 +PIC.Core.DRAGNET.drg09.mpi_nic= +PIC.Core.DRAGNET.drg09.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg09.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg10.host=drg10 +PIC.Core.DRAGNET.drg10.cpu=-1 +PIC.Core.DRAGNET.drg10.mpi_nic= +PIC.Core.DRAGNET.drg10.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg10.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg11.host=drg11 +PIC.Core.DRAGNET.drg11.cpu=-1 +PIC.Core.DRAGNET.drg11.mpi_nic= +PIC.Core.DRAGNET.drg11.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg11.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg12.host=drg12 +PIC.Core.DRAGNET.drg12.cpu=-1 +PIC.Core.DRAGNET.drg12.mpi_nic= +PIC.Core.DRAGNET.drg12.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg12.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg13.host=drg13 +PIC.Core.DRAGNET.drg13.cpu=-1 +PIC.Core.DRAGNET.drg13.mpi_nic= +PIC.Core.DRAGNET.drg13.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg13.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg14.host=drg14 +PIC.Core.DRAGNET.drg14.cpu=-1 +PIC.Core.DRAGNET.drg14.mpi_nic= +PIC.Core.DRAGNET.drg14.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg14.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg15.host=drg15 +PIC.Core.DRAGNET.drg15.cpu=-1 +PIC.Core.DRAGNET.drg15.mpi_nic= +PIC.Core.DRAGNET.drg15.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg15.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg16.host=drg16 +PIC.Core.DRAGNET.drg16.cpu=-1 +PIC.Core.DRAGNET.drg16.mpi_nic= +PIC.Core.DRAGNET.drg16.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg16.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg17.host=drg17 +PIC.Core.DRAGNET.drg17.cpu=-1 +PIC.Core.DRAGNET.drg17.mpi_nic= +PIC.Core.DRAGNET.drg17.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg17.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg18.host=drg18 +PIC.Core.DRAGNET.drg18.cpu=-1 +PIC.Core.DRAGNET.drg18.mpi_nic= +PIC.Core.DRAGNET.drg18.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg18.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg19.host=drg19 +PIC.Core.DRAGNET.drg19.cpu=-1 +PIC.Core.DRAGNET.drg19.mpi_nic= +PIC.Core.DRAGNET.drg19.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg19.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg20.host=drg20 +PIC.Core.DRAGNET.drg20.cpu=-1 +PIC.Core.DRAGNET.drg20.mpi_nic= +PIC.Core.DRAGNET.drg20.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg20.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg21.host=drg21 +PIC.Core.DRAGNET.drg21.cpu=-1 +PIC.Core.DRAGNET.drg21.mpi_nic= +PIC.Core.DRAGNET.drg21.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg21.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg22.host=drg22 +PIC.Core.DRAGNET.drg22.cpu=-1 +PIC.Core.DRAGNET.drg22.mpi_nic= +PIC.Core.DRAGNET.drg22.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg22.gpus=[0, 1, 2, 3] + +PIC.Core.DRAGNET.drg23.host=drg23 +PIC.Core.DRAGNET.drg23.cpu=-1 +PIC.Core.DRAGNET.drg23.mpi_nic= +PIC.Core.DRAGNET.drg23.out_nic=[CEP4:ib0,DRAGNET:ib0] +PIC.Core.DRAGNET.drg23.gpus=[0, 1, 2, 3] + diff --git a/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareUsed.parset b/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareUsed.parset index ac5194cf5ea..5509586a494 100644 --- a/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareUsed.parset +++ b/RTCP/Cobalt/GPUProc/etc/parset-additions.d/default/HardwareUsed.parset @@ -23,3 +23,26 @@ Cobalt.Nodes = [ cbt008_1 ] +DRAGNET.Nodes = [ + drg01, + drg02, + drg03, + drg04, + drg05, + drg06, + drg07, + drg08, + drg09, + drg10, + drg11, + drg12, + drg13, + drg14, + drg15, + drg16, + drg17, + drg18, + drg19, + drg20 +] + diff --git a/RTCP/Cobalt/GPUProc/etc/parset-additions.d/rspraw-enable.parset.OBSID b/RTCP/Cobalt/GPUProc/etc/parset-additions.d/rspraw-enable.parset.OBSID new file mode 100644 index 00000000000..70b247ec737 --- /dev/null +++ b/RTCP/Cobalt/GPUProc/etc/parset-additions.d/rspraw-enable.parset.OBSID @@ -0,0 +1,58 @@ +# rspraw-enable.parset.OBSID: override COBALT settings to enable RSP raw antenna field output +# +# Basic Usage: After preparing an observation with desired station and freq settings, but before the MACScheduler starts it up, +# run as lofarsys on the COBALT head node: +# cd $LOFARROOT/etc/parset-additions.d/override && cp ../rspraw-enable.parset.OBSID rspraw-enable.parset.123456 +# where 123456 is the observation ID. +# +# NOTE: This is a COBALT-only expert mode setting adjustment. While you really have to outstrip yourself to +# screw up the system beyond this observation, little customization effort is needed to screw up this observation. +# +# $Id$ + +# By default, disable correlated and beamformed data. +# You can comment out or enable these to *also* get correlated and/or beamformed output; +# assuming you specified all correlator and/or beamformer settings properly. +Observation.DataProducts.Output_Correlated.enabled=false +Observation.DataProducts.Output_Beamformed.enabled=false + + +# Enable RSP raw output +Observation.DataProducts.Output_RSPRaw.enabled=true + +# The following RSP raw settings are commented out by default, because then they are auto-detected from +# correlated and/or beamformed settings, even if those are disabled just above. Feel free to customize. + +# Override start/stop times: Observation runs as specified, but RSP raw data is only written out for this interval. +# The interval must be within the observation start/stop times interval. +# Default: observation start/stop time +#Cobalt.RSPRaw.startTime=2017-01-29 10:00:00 +#Cobalt.RSPRaw.stopTime=2017-01-29 11:00:00 + +# Override station list: Observation uses stations as specified, but RSP raw data is only written for these stations. +# The list must be a subset of the observation station set. +# Default: the full set of observation stations +#Cobalt.RSPRaw.stationList=[CS002, CS003] + +# Override beamlets: Observation uses beam and frequency settings as specified, +# but RSP raw data is only written for the first N beamlets (whatever beams/subbands that corresponds to...). +# The value is a list: one value per sending RSP board (stream) for all stations(!), thus typically a list of (at least) length 4. +# Each value must be within the valid range for the bit mode: +# 16 bit: [ 61, 61, 61, 61] (thus max 244) +# 8 bit: [122, 122, 122, 122] (thus max 488) +# 4 bit: [244, 244, 244, 244] (but the stations can handle a max total of 966 (not 976); unclear how it's spread over the RSP boards) +# Default: all observation beamlets +#Cobalt.RSPRaw.nrBeamletsPerBoardList=[122, 122, 122, 122] + +# Override filenames and locations where RSP raw data is written to. +# Note that the hostnames must be on the COBALT/CEP4 infiniband network (10G may also work; you may need to also override the network interface bound to...). +# Prefer fully qualified domain names (FQDN), or CEP4:/path (per file) and the system will assign CEP4 nodes. +# Note that you must provide (at least) enough filenames and locations! Typically, 4x the number of antenna fields for RSP raw output. +# WARNING: Auto-detection fills in the observation ID, but if you override you cannot: +# another observation with the same customized override file will overwrite previously dumped data! +# Default: Hostnames in locations: round robin over the set of correlated + beamformed hostnames. +# Filenames format: Lxxx_yyy_zzz_rsp.raw where xxx=OBS_ID, yyy=ANT_FIELD_NAME, zzz=BOARD_NR (+ Lxxx_yyy_zzz_rsp.raw.parset files). +#Observation.DataProducts.Output_RSPRaw.filenames=[L123456_CS002HBA0_0_rsp.raw, L123456_CS002HBA0_1_rsp.raw, L123456_CS002HBA0_2_rsp.raw, L123456_CS002HBA0_3_rsp.raw, L123456_CS002HBA1_0_rsp.raw, L123456_CS002HBA1_1_rsp.raw, L123456_CS002HBA1_2_rsp.raw, L123456_CS002HBA1_3_rsp.raw, L123456_CS003HBA0_0_rsp.raw, L123456_CS003HBA0_1_rsp.raw, L123456_CS003HBA0_2_rsp.raw, L123456_CS003HBA0_3_rsp.raw, L123456_CS003HBA1_0_rsp.raw, L123456_CS003HBA1_1_rsp.raw, L123456_CS003HBA1_2_rsp.raw, L123456_CS003HBA1_3_rsp.raw] +#Observation.DataProducts.Output_RSPRaw.locations=[CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs,CEP4:/data/projects/2017LOFAROBS/L123456/cs] +#Observation.DataProducts.Output_RSPRaw.storageClusterName=CEP4 + diff --git a/RTCP/Cobalt/GPUProc/src/MPIReceiver.h b/RTCP/Cobalt/GPUProc/src/MPIReceiver.h index 4ca0040b425..eeccb9516c7 100644 --- a/RTCP/Cobalt/GPUProc/src/MPIReceiver.h +++ b/RTCP/Cobalt/GPUProc/src/MPIReceiver.h @@ -21,8 +21,8 @@ // \file // Include for processor optimalizetion functionality -#ifndef LOFAR_GPUPROC_MPI_UTILS_H -#define LOFAR_GPUPROC_MPI_UTILS_H +#ifndef LOFAR_GPUPROC_MPI_RECEIVER_H +#define LOFAR_GPUPROC_MPI_RECEIVER_H #include <InputProc/Transpose/MPIUtil.h> #include <InputProc/SampleType.h> diff --git a/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc b/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc index 7d2775bec32..438b1254048 100644 --- a/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc +++ b/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc @@ -1,5 +1,5 @@ //# StationInput.cc: Routines to manage I/O from the stations. -//# Copyright (C) 2012-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2012-2013, 2017 ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -34,6 +34,8 @@ #include <map> #include <vector> #include <string> +#include <algorithm> +#include <memory> #include <boost/format.hpp> #include <Common/LofarLogger.h> @@ -158,7 +160,8 @@ namespace LOFAR { StationInput::StationInput( const Parset &ps, size_t stationIdx, - const SubbandDistribution &subbandDistribution ) + const SubbandDistribution &subbandDistribution, + unsigned hostID ) : ps(ps), stationIdx(stationIdx), @@ -175,14 +178,45 @@ namespace LOFAR { targetSubbands(values(subbandDistribution)), beamletIndices(generateBeamletIndices()) { - for (size_t i = 0; i < nrBoards; ++i) { - rspDataPool.push_back(new Pool<RSPData>(str(format("StationInput::rspDataPool[%u] [station %s]") % i % stationID.name()), ps.settings.realTime)); - } + ASSERTSTR(nrBoards > 0, logPrefix << "No input streams"); // Log all input descriptions LOG_INFO_STR(logPrefix << "Input streams: " << ps.settings.antennaFields.at(stationIdx).inputStreams); - ASSERTSTR(nrBoards > 0, logPrefix << "No input streams"); + for (unsigned i = 0; i < nrBoards; ++i) { + rspDataPool.push_back(new Pool<RSPData>(str(format("StationInput::rspDataPool[%u] [station %s]") % i % stationID.name()), + ps.settings.realTime)); + } + + if (ps.settings.rspRaw.enabled && + std::find(ps.settings.rspRaw.antennaFieldNames.begin(), ps.settings.rspRaw.antennaFieldNames.end(), + stationID.name()) != ps.settings.rspRaw.antennaFieldNames.end()) { + unsigned maxNrPacketsToSend = NONRT_PACKET_BATCH_SIZE; + time_t connTimeout = 0; + if (ps.settings.realTime) { + maxNrPacketsToSend = RT_PACKET_BATCH_SIZE; + connTimeout = std::time(NULL) + 3; // a few secs from now + } + + rspRawSenders.resize(nrBoards); + #pragma omp parallel for num_threads(nrBoards) // easy way to apply a single connTimeout to all + for (unsigned i = 0; i < nrBoards; ++i) { + unsigned fileIdx = ps.getRSPRawOutputStreamIdx(stationID.name(), i); +// TODO: produce UDP stream descriptor for piggy backing instead of TCP for RSP raw storage + string desc = getStreamDescriptorBetweenIONandStorage(ps, RSP_RAW_DATA, fileIdx, + hostID < ps.settings.nodes.size() ? ps.settings.nodes[hostID].out_nic : ""); + LOG_INFO_STR(logPrefix << "Opening RSP raw output stream for data from antenna field " << + stationID.name() << " board " << i << " with stream descriptor " << desc); + + try { + new (&rspRawSenders[i]) RSPRawSender(maxNrPacketsToSend, ps.settings.rspRaw.nrBeamletsPerBoardList.at(i), + desc, connTimeout); // pre-C++11 has no emplace_back(), so use placement new + } catch (Exception &exc) { // TimeOutException, SystemCallException + LOG_ERROR_STR(logPrefix << "RSPRawSender creation failure for stream " << desc << ": " << exc); + new (&rspRawSenders[i]) RSPRawSender; + } + } + } } @@ -211,8 +245,8 @@ namespace LOFAR { // The corresponding (board,slot) combination for that subband, // for this station. - const size_t board = ps.settings.antennaFields[stationIdx].rspBoardMap[sb]; - const size_t slot = ps.settings.antennaFields[stationIdx].rspSlotMap[sb]; + const unsigned board = ps.settings.antennaFields[stationIdx].rspBoardMap[sb]; + const unsigned slot = ps.settings.antennaFields[stationIdx].rspSlotMap[sb]; ASSERT(board < nrBoards); ASSERT(slot < mode.nrBeamletsPerBoard()); @@ -226,7 +260,7 @@ namespace LOFAR { } - SmartPtr<Stream> StationInput::inputStream(size_t board) const + SmartPtr<Stream> StationInput::inputStream(unsigned board) const { SmartPtr<Stream> stream; @@ -267,7 +301,7 @@ namespace LOFAR { } - void StationInput::readRSPRealTime( size_t board, MACIO::RTmetadata &mdLogger, + void StationInput::readRSPRealTime( unsigned board, MACIO::RTmetadata &mdLogger, const string &mdKeyPrefix ) { /* @@ -345,7 +379,7 @@ namespace LOFAR { } else { // One core can't handle the load, so use multiple # pragma omp parallel for num_threads(nrBoards) - for (size_t board = 0; board < nrBoards; board++) { + for (unsigned board = 0; board < nrBoards; board++) { //NSTimer copyRSPTimer(str(format("%s [board %i] copy RSP -> block") % logPrefix % board), true, true); OMPThread::ScopedName sn(str(format("%s wr %u") % ps.settings.antennaFields.at(stationIdx).name % board)); @@ -361,25 +395,44 @@ namespace LOFAR { // Write valid packets to the current and/or next packet //copyRSPTimer.start(); - for (size_t p = 0; p < RT_PACKET_BATCH_SIZE; ++p) { - struct RSP &packet = rspData->packets[p]; + if (ps.settings.correlator.enabled || ps.settings.beamFormer.enabled) { + for (unsigned p = 0; p < RT_PACKET_BATCH_SIZE; ++p) { + struct RSP &packet = rspData->packets[p]; - if (packet.payloadError()) - continue; + if (packet.payloadError()) + continue; - if (current.write(packet, beamletIndices, nrBeamletIndices) - && next) { - // We have data (potentially) spilling into `next'. + if (current.write(packet, beamletIndices, nrBeamletIndices) && next) { + // We have data (potentially) spilling into `next'. - if (next->write(packet, beamletIndices, nrBeamletIndices)) { - // Only emit log lines every minute seconds to prevent spam - if (loggedSeenFutureData + mode.secondsToSamples(60) < now) { - LOG_ERROR_STR(logPrefix << "Received data for several blocks into the future -- discarding."); - loggedSeenFutureData = now; + if (next->write(packet, beamletIndices, nrBeamletIndices)) { + // Only emit log lines every minute seconds to prevent spam + if (loggedSeenFutureData + mode.secondsToSamples(60) < now) { + LOG_ERROR_STR(logPrefix << "Received data for several blocks into the future -- discarding."); + loggedSeenFutureData = now; + } } } } } + + if (!rspRawSenders.empty() && rspRawSenders[board].initialized()) { + // Quick check on timestamp + // Don't cater for out-of-order input: the extra logic is not worth the benefit. + // We may not always get all RT_PACKET_BATCH_SIZE. PacketReader sets payloadError and + // timestamp as invalid in remaining entries. Such timestamps are filtered here too. + unsigned nrPackets = RT_PACKET_BATCH_SIZE; + for (unsigned p = 0; p < nrPackets; p++) { + if (rspData->packets[p].header.timestamp >= ps.settings.rspRaw.stopTime || + rspData->packets[p].header.timestamp < ps.settings.rspRaw.startTime) { + nrPackets = p; + break; + } + } + if (nrPackets > 0) { + rspRawSenders[board].trySend(&rspData->packets[0], nrPackets); + } + } //copyRSPTimer.stop(); outputQueue.append(rspData); @@ -415,7 +468,7 @@ namespace LOFAR { vector<bool> read_next_packet(nrBoards, true); for(;;) { - for(size_t board = 0; board < nrBoards; board++) { + for (unsigned board = 0; board < nrBoards; board++) { if (!read_next_packet[board] || !readers[board]) continue; @@ -433,18 +486,18 @@ namespace LOFAR { } // Determine which board provided the youngest packet - int youngest = -1; + unsigned youngest = nrBoards; // init to special (invalid) value - for (size_t board = 0; board < nrBoards; board++) { + for (unsigned board = 0; board < nrBoards; board++) { if (!readers[board]) continue; - if (youngest == -1 || last_packets[youngest].timeStamp() > last_packets[board].timeStamp()) + if (youngest == nrBoards || last_packets[youngest].timeStamp() > last_packets[board].timeStamp()) youngest = board; } // Break if all streams turned out to be inactive - if (youngest == -1) + if (youngest == nrBoards) break; // Emit youngest packet @@ -463,8 +516,8 @@ namespace LOFAR { // Next packet should only be read from the stream we // emitted from - for(size_t board = 0; board < nrBoards; board++) - read_next_packet[board] = (board == (size_t)youngest); + for (unsigned board = 0; board < nrBoards; board++) + read_next_packet[board] = (board == youngest); } // Signal EOD by inserting a packet beyond obs end @@ -509,13 +562,22 @@ namespace LOFAR { // Only packet 0 is used in non-rt mode - if (current.write(data->packets[0], beamletIndices, nrBeamletIndices)) { - // We have data (potentially) spilling into `next'. - if (!next || next->write(data->packets[0], beamletIndices, nrBeamletIndices)) { - // Data is even later than next? Put this data back for a future block. - rspDataPool[0]->filled.prepend(data); - ASSERT(!data); - return; + if (ps.settings.correlator.enabled || ps.settings.beamFormer.enabled) { + if (current.write(data->packets[0], beamletIndices, nrBeamletIndices)) { + // We have data (potentially) spilling into `next'. + if (!next || next->write(data->packets[0], beamletIndices, nrBeamletIndices)) { + // Data is even later than next? Put this data back for a future block. + rspDataPool[0]->filled.prepend(data); + ASSERT(!data); + return; + } + } + } + + if (!rspRawSenders.empty() && rspRawSenders[data->board].initialized()) { + if (data->packets[0].header.timestamp < ps.settings.rspRaw.stopTime && + data->packets[0].header.timestamp >= ps.settings.rspRaw.startTime) { + rspRawSenders[data->board].trySend(&data->packets[0], NONRT_PACKET_BATCH_SIZE); } } @@ -573,7 +635,7 @@ namespace LOFAR { if (ps.settings.realTime) { #pragma omp parallel for num_threads(nrBoards) - for(size_t board = 0; board < nrBoards; board++) { + for (unsigned board = 0; board < nrBoards; board++) { try { OMPThreadSet::ScopedRun sr(packetReaderThreads); OMPThread::ScopedName sn(str(format("%s rd %u") % ps.settings.antennaFields.at(stationIdx).name % board)); @@ -651,13 +713,13 @@ namespace LOFAR { template<typename SampleT> void sendInputToPipeline(const Parset &ps, - size_t stationIdx, const SubbandDistribution &subbandDistribution, + size_t stationIdx, const SubbandDistribution &subbandDistribution, unsigned hostID, MACIO::RTmetadata &mdLogger, const string &mdKeyPrefix, Trigger *stopSwitch) { // sanity check: Find out if we should actual start working here. StationMetaData<SampleT> sm(ps, stationIdx, subbandDistribution); - StationInput si(ps, stationIdx, subbandDistribution); + StationInput si(ps, stationIdx, subbandDistribution, hostID); const struct StationID stationID(StationID::parseFullFieldName( ps.settings.antennaFields.at(stationIdx).name)); @@ -721,30 +783,29 @@ namespace LOFAR { } void sendInputToPipeline(const Parset &ps, size_t stationIdx, - const SubbandDistribution &subbandDistribution, + const SubbandDistribution &subbandDistribution, unsigned hostID, MACIO::RTmetadata &mdLogger, const string &mdKeyPrefix, Trigger *stopSwitch) { switch (ps.nrBitsPerSample()) { default: case 16: sendInputToPipeline< SampleType<i16complex> >(ps, stationIdx, - subbandDistribution, + subbandDistribution, hostID, mdLogger, mdKeyPrefix, stopSwitch); break; case 8: sendInputToPipeline< SampleType< i8complex> >(ps, stationIdx, - subbandDistribution, + subbandDistribution, hostID, mdLogger, mdKeyPrefix, stopSwitch); break; case 4: sendInputToPipeline< SampleType< i4complex> >(ps, stationIdx, - subbandDistribution, + subbandDistribution, hostID, mdLogger, mdKeyPrefix, stopSwitch); break; } } } } - diff --git a/RTCP/Cobalt/GPUProc/src/Station/StationInput.h b/RTCP/Cobalt/GPUProc/src/Station/StationInput.h index b3f655b4dde..45a2b88ef09 100644 --- a/RTCP/Cobalt/GPUProc/src/Station/StationInput.h +++ b/RTCP/Cobalt/GPUProc/src/Station/StationInput.h @@ -1,5 +1,5 @@ //# StationInput.h: Routines to manage I/O from the stations. -//# Copyright (C) 2012-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2012-2013, 2017 ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -34,10 +34,11 @@ #include <CoInterface/SubbandMetaData.h> #include <CoInterface/Queue.h> #include <CoInterface/BestEffortQueue.h> +#include <CoInterface/RSP.h> +#include <CoInterface/RSPRawTransfer.h> #include <InputProc/Buffer/StationID.h> #include <InputProc/Buffer/BoardMode.h> #include <InputProc/RSPTimeStamp.h> -#include <InputProc/Station/RSP.h> #include "StationTranspose.h" @@ -76,7 +77,8 @@ namespace LOFAR { class StationInput { public: StationInput( const Parset &ps, size_t stationIdx, - const SubbandDistribution &subbandDistribution ); + const SubbandDistribution &subbandDistribution, + unsigned hostID = 0 ); template <typename SampleT> void processInput( Queue< SmartPtr< MPIData<SampleT> > > &inputQueue, @@ -86,14 +88,14 @@ namespace LOFAR { private: // Each packet is expected to have 16 samples per subband, i.e. ~80 us worth of data @ 200 MHz. // So 512 packets is ~40 ms of data. - static const unsigned RT_PACKET_BATCH_SIZE = 512; + static const unsigned RT_PACKET_BATCH_SIZE = 512; // RSP raw sendmmsg(2) needs this to be <= UIO_MAXIOV (1024) static const unsigned NONRT_PACKET_BATCH_SIZE = 1; // Data received from an RSP board struct RSPData { std::vector<struct RSP> packets; - size_t board; // annotation used in non-rt mode + unsigned board; // annotation used in non-rt mode RSPData(size_t numPackets): packets(numPackets) @@ -109,8 +111,9 @@ namespace LOFAR { const std::string logPrefix; const BoardMode mode; - const size_t nrBoards; - std::vector< SmartPtr< Pool< RSPData > > > rspDataPool; // [nrboards] + const unsigned nrBoards; + std::vector< SmartPtr< Pool< RSPData > > > rspDataPool; // [nrBoards] + std::vector<RSPRawSender> rspRawSenders; // [nrBoards] if RSP raw enabled and the antenna field is selected, else [] // Whether we emitted certain errors (to prevent log spam) TimeStamp loggedSeenFutureData; @@ -125,7 +128,7 @@ namespace LOFAR { MultiDimArray<ssize_t, 2> generateBeamletIndices(); - SmartPtr<Stream> inputStream(size_t board) const; + SmartPtr<Stream> inputStream(unsigned board) const; /* * Reads data from all the station input streams, and puts their packets in rspDataPool. @@ -145,7 +148,7 @@ namespace LOFAR { * * Read data from one board in real-time mode. */ - void readRSPRealTime( size_t board, MACIO::RTmetadata &mdLogger, + void readRSPRealTime( unsigned board, MACIO::RTmetadata &mdLogger, const std::string &mdKeyPrefix ); /* @@ -166,6 +169,7 @@ namespace LOFAR { void sendInputToPipeline(const Parset &ps, size_t stationIdx, const SubbandDistribution &subbandDistribution, + unsigned hostID, // mpi rank for this node MACIO::RTmetadata &mdLogger, const std::string &mdKeyPrefix, Trigger *stopSwitch = NULL); diff --git a/RTCP/Cobalt/GPUProc/src/Station/StationTranspose.h b/RTCP/Cobalt/GPUProc/src/Station/StationTranspose.h index 6df17f21c03..16211ae2b93 100644 --- a/RTCP/Cobalt/GPUProc/src/Station/StationTranspose.h +++ b/RTCP/Cobalt/GPUProc/src/Station/StationTranspose.h @@ -29,8 +29,8 @@ #include <CoInterface/Parset.h> #include <CoInterface/Queue.h> #include <CoInterface/SubbandMetaData.h> +#include <CoInterface/RSP.h> #include <InputProc/RSPTimeStamp.h> -#include <InputProc/Station/RSP.h> #include <InputProc/Transpose/MPIProtocol.h> #include <InputProc/Transpose/MPIUtil.h> diff --git a/RTCP/Cobalt/GPUProc/src/cuda/Pipelines/Pipeline.cc b/RTCP/Cobalt/GPUProc/src/cuda/Pipelines/Pipeline.cc index 67e24f2d7b5..51370ec4a41 100644 --- a/RTCP/Cobalt/GPUProc/src/cuda/Pipelines/Pipeline.cc +++ b/RTCP/Cobalt/GPUProc/src/cuda/Pipelines/Pipeline.cc @@ -146,7 +146,8 @@ namespace LOFAR // be in bulk: if processing is cheap, all subbands will be output right after they have been received. // // Allow queue to drop items older than 3 seconds. - multiSender(hostMap(ps, subbandIndices, hostID), ps, 3.0, hostID < ps.settings.nodes.size() ? ps.settings.nodes.at(hostID).out_nic : ""), + multiSender(hostMap(ps, subbandIndices, hostID), ps, 3.0, + hostID < ps.settings.nodes.size() ? ps.settings.nodes[hostID].out_nic : ""), hostID(hostID) { ASSERTSTR(!devices.empty(), "Not bound to any GPU!"); @@ -830,7 +831,7 @@ namespace LOFAR if (ps.settings.correlator.enabled) { const string desc = getStreamDescriptorBetweenIONandStorage(ps, CORRELATED_DATA, globalSubbandIdx, - hostID < ps.settings.nodes.size() ? ps.settings.nodes.at(hostID).out_nic : ""); + hostID < ps.settings.nodes.size() ? ps.settings.nodes[hostID].out_nic : ""); try { outputStream = createStream(desc, false, 0); diff --git a/RTCP/Cobalt/GPUProc/src/rtcp.cc b/RTCP/Cobalt/GPUProc/src/rtcp.cc index 5195a218163..20ee60d73c7 100644 --- a/RTCP/Cobalt/GPUProc/src/rtcp.cc +++ b/RTCP/Cobalt/GPUProc/src/rtcp.cc @@ -285,11 +285,13 @@ int main(int argc, char **argv) if(mpi.rank() >= 0 && (size_t)mpi.rank() < ps.settings.nodes.size()) { struct ObservationSettings::Node mynode = ps.settings.nodes.at(mpi.rank()); - // set the processor affinity before any threads are created - setProcessorAffinity(mynode.cpu); + if (mynode.cpu != -1) { + // set the processor affinity before any threads are created + setProcessorAffinity(mynode.cpu); + } #ifdef HAVE_LIBNUMA - if (numa_available() != -1) { + if (mynode.cpu != -1 && numa_available() != -1) { // force node + memory binding for future allocations struct bitmask *numa_node = numa_allocate_nodemask(); numa_bitmask_clearall(numa_node); @@ -315,7 +317,7 @@ int main(int argc, char **argv) LOG_DEBUG_STR("Bound to memory on nodes " << nodestrs); } else { - LOG_WARN("Cannot bind memory (libnuma says there is no numa available)"); + LOG_INFO("Cannot bind memory: cpu nr to bind to is set to -1 or libnuma reports NUMA is not available"); } #else LOG_WARN("Cannot bind memory (no libnuma support)"); @@ -388,12 +390,13 @@ int main(int argc, char **argv) // Creation of pipelines cause fork/exec, which we need to // do before we start doing anything fancy with libraries and threads. - if (subbandIndices.empty()) { - // no operation -- don't even create a pipeline! - pipeline = NULL; - } else { + if ((ps.settings.correlator.enabled || ps.settings.beamFormer.enabled) && + !subbandIndices.empty()) { pipeline = new Pipeline(ps, subbandIndices, devices, MPI_receive_pool, mdLogger, mdKeyPrefix, mpi.rank()); + } else { + // RSP raw data output or piggy-backing only, or software test without pipeline + pipeline = NULL; } // After pipeline creation (post-fork()), allow creation of a thread to send @@ -520,7 +523,7 @@ int main(int argc, char **argv) mdLogger.log(mdKeyPrefixInputProc + PN_CSI_CPU, cpuNr); - sendInputToPipeline(ps, stat, subbandDistribution, + sendInputToPipeline(ps, stat, subbandDistribution, mpi.rank(), mdLogger, mdKeyPrefixInputProc, &stopSwitch); } } @@ -538,8 +541,9 @@ int main(int argc, char **argv) { OMPThread::ScopedName sn("obs process"); - // Process station data - if (!subbandDistribution[mpi.rank()].empty()) { + // Process station data if needed and if any + if ((ps.settings.correlator.enabled || ps.settings.beamFormer.enabled) && + !subbandDistribution[mpi.rank()].empty()) { pipeline->processObservation(); } } diff --git a/RTCP/Cobalt/GPUProc/src/scripts/cobalt_functions.sh b/RTCP/Cobalt/GPUProc/src/scripts/cobalt_functions.sh index 263ec2aef3b..a7a79ecfcd8 100755 --- a/RTCP/Cobalt/GPUProc/src/scripts/cobalt_functions.sh +++ b/RTCP/Cobalt/GPUProc/src/scripts/cobalt_functions.sh @@ -36,7 +36,7 @@ function setkey { echo "$KEY = $VAL" >> "$PARSET" } -COBALT_DATAPRODUCTS="Correlated CoherentStokes IncoherentStokes" +COBALT_DATAPRODUCTS="Correlated CoherentStokes IncoherentStokes RSPRaw" function read_cluster_model { # HACK: Search for first cluster, and assume they're all the same. We support only output diff --git a/RTCP/Cobalt/GPUProc/test/tMPIReceive.cc b/RTCP/Cobalt/GPUProc/test/tMPIReceive.cc index a5ae57a1491..88673b74b50 100644 --- a/RTCP/Cobalt/GPUProc/test/tMPIReceive.cc +++ b/RTCP/Cobalt/GPUProc/test/tMPIReceive.cc @@ -106,7 +106,7 @@ int main(int argc, char **argv) } MACIO::RTmetadata rtmd(ps.settings.observationID, "", ""); - sendInputToPipeline(ps, stat, subbandDistribution, + sendInputToPipeline(ps, stat, subbandDistribution, mpi.rank(), rtmd, "rtmd key prefix"); cout << "First ended" << endl; } diff --git a/RTCP/Cobalt/InputProc/src/Station/Generator.h b/RTCP/Cobalt/InputProc/src/Station/Generator.h index 22fcdcde5cb..e3d4831cae2 100644 --- a/RTCP/Cobalt/InputProc/src/Station/Generator.h +++ b/RTCP/Cobalt/InputProc/src/Station/Generator.h @@ -26,13 +26,13 @@ #include <Stream/Stream.h> #include <CoInterface/SmartPtr.h> +#include <CoInterface/RSP.h> #include <InputProc/RSPBoards.h> #include <InputProc/Buffer/StationID.h> #include <InputProc/RSPTimeStamp.h> #include "PacketFactory.h" -#include "RSP.h" namespace LOFAR { diff --git a/RTCP/Cobalt/InputProc/src/Station/PacketFactory.h b/RTCP/Cobalt/InputProc/src/Station/PacketFactory.h index 14d0166febc..900f7ec31cc 100644 --- a/RTCP/Cobalt/InputProc/src/Station/PacketFactory.h +++ b/RTCP/Cobalt/InputProc/src/Station/PacketFactory.h @@ -22,11 +22,10 @@ #ifndef LOFAR_INPUT_PROC_PACKETFACTORY_H #define LOFAR_INPUT_PROC_PACKETFACTORY_H +#include <CoInterface/RSP.h> #include <InputProc/RSPTimeStamp.h> #include <InputProc/Buffer/BoardMode.h> -#include "RSP.h" - namespace LOFAR { namespace Cobalt diff --git a/RTCP/Cobalt/InputProc/src/Station/PacketReader.cc b/RTCP/Cobalt/InputProc/src/Station/PacketReader.cc index 1047c1fa2d4..8cad4fddd52 100644 --- a/RTCP/Cobalt/InputProc/src/Station/PacketReader.cc +++ b/RTCP/Cobalt/InputProc/src/Station/PacketReader.cc @@ -40,18 +40,17 @@ namespace LOFAR PacketReader::PacketReader( const std::string &logPrefix, Stream &inputStream, const BoardMode &mode ) - : - logPrefix(str(boost::format("%s [PacketReader] ") % logPrefix)), + : mode(mode), inputStream(inputStream), - mode(mode), + logPrefix(str(boost::format("%s [PacketReader] ") % logPrefix)), + hadSizeError(false), nrReceived(0), nrBadMode(0), nrBadTime(0), nrBadData(0), nrBadOther(0), - hadSizeError(false), - lastLogTime(0) + lastLogTime(0.0) { // Partial reads are not supported on UDP streams, because each read() // will consume a full packet. @@ -74,7 +73,9 @@ namespace LOFAR if (inputIsUDP) { SocketStream &sstream = dynamic_cast<SocketStream&>(inputStream); - vector<unsigned> recvdSizes(packets.size()); + if (recvdSizes.size() != packets.size()) { + recvdSizes.resize(packets.size()); + } numRead = sstream.recvmmsg(&packets[0], sizeof(struct RSP), recvdSizes); nrReceived += numRead; @@ -93,6 +94,7 @@ namespace LOFAR // mark unused packet buffers as invalid for (size_t i = numRead; i < packets.size(); ++i) { packets[i].payloadError(true); + packets[i].timeStampError(); // easier for RSP raw code to filter } } @@ -134,7 +136,7 @@ namespace LOFAR } // illegal version means illegal packet - if (packet.header.version < 2) { + if (packet.header.version < 3) { // This mainly catches packets that are all zero (f.e. /dev/zero or // null: streams). ++nrBadOther; diff --git a/RTCP/Cobalt/InputProc/src/Station/PacketReader.h b/RTCP/Cobalt/InputProc/src/Station/PacketReader.h index 2140a4c2717..323a31047ed 100644 --- a/RTCP/Cobalt/InputProc/src/Station/PacketReader.h +++ b/RTCP/Cobalt/InputProc/src/Station/PacketReader.h @@ -22,13 +22,13 @@ #define LOFAR_INPUT_PROC_PACKETREADER_H #include <string> +#include <vector> #include <Common/Exception.h> #include <Stream/SocketStream.h> #include <MACIO/RTmetadata.h> -#include <InputProc/Buffer/BoardMode.h> - -#include "RSP.h" +#include <CoInterface/RSP.h> +#include "../Buffer/BoardMode.h" namespace LOFAR { @@ -62,29 +62,32 @@ namespace LOFAR const std::string &mdKeyPrefix); private: - const std::string logPrefix; + // The mode against which to validate (ignored if mode == MODE_ANY) + const BoardMode mode; // The stream from which packets are read. Stream &inputStream; - // The mode against which to validate (ignored if mode == MODE_ANY) - const BoardMode mode; + // For SocketStream recvmmsg() to indicate max nr packets to receive and to return bytes sent. + std::vector<unsigned> recvdSizes; + + const std::string logPrefix; // Whether inputStream is an UDP stream // UDP streams do not allow partial reads and can use recvmmsg(2) (Linux). bool inputIsUDP; // Statistics covering the packets read so far + bool hadSizeError; // already reported about wrongly sized packets since last logStatistics() size_t nrReceived; // nr. of packets received size_t nrBadMode; // nr. of packets with wrong mode (clock, bit mode) size_t nrBadTime; // nr. of packets with an illegal time stamp size_t nrBadData; // nr. of packets with payload errors size_t nrBadOther; // nr. of packets that are bad in another fashion (illegal header, packet size, etc) - bool hadSizeError; // already reported about wrongly sized packets since last logStatistics() - double lastLogTime; // time since last log print, to monitor data rates + // numbytes is the actually received size, as indicated by the kernel bool validatePacket(const struct RSP &packet, size_t numbytes); }; diff --git a/RTCP/Cobalt/InputProc/src/Station/PacketStream.h b/RTCP/Cobalt/InputProc/src/Station/PacketStream.h index 0e61ba0eb32..38c5baf1179 100644 --- a/RTCP/Cobalt/InputProc/src/Station/PacketStream.h +++ b/RTCP/Cobalt/InputProc/src/Station/PacketStream.h @@ -24,9 +24,9 @@ #include <Stream/Stream.h> #include <Common/Thread/Cancellation.h> -#include <InputProc/RSPTimeStamp.h> +#include <CoInterface/RSP.h> +#include "../RSPTimeStamp.h" #include "PacketFactory.h" -#include "RSP.h" namespace LOFAR { @@ -53,23 +53,26 @@ namespace LOFAR { Cancellation::point(); - if (current >= to) + if (size == 0) { + return 0; + } + + if (current >= to) { THROW(EndOfStreamException, "No data beyond " << to); + } if (offset == 0) { // generate new packet factory.makePacket(packet, current, boardNr); - current += packet.header.nrBlocks; } - size_t numBytes = std::min(packet.packetSize() - offset, size); - + size_t pktSize = packet.packetSize(); + size_t numBytes = std::min(pktSize - offset, size); memcpy(ptr, reinterpret_cast<char*>(&packet) + offset, numBytes); offset += numBytes; - - if (offset == packet.packetSize()) { + if (offset == pktSize) { // written full packet, so we'll need a new one on next read offset = 0; } @@ -77,13 +80,60 @@ namespace LOFAR return numBytes; } - virtual size_t tryWrite(const void *ptr, size_t size) + virtual size_t tryWrite(const void * /*ptr*/, size_t /*size*/) { - // not supported - (void)ptr; - (void)size; + THROW(NotImplemented, "Writing to PacketStream is not supported"); + } - THROW(EndOfStreamException, "Writing to PacketStream is not supported"); + virtual size_t tryReadv(const struct iovec *iov, int iovcnt) + { + Cancellation::point(); + + size_t nread = 0; + for (int i = 0; i < iovcnt; i++) { + if (iov[i].iov_len == 0) { + continue; + } + + if (current >= to) { + if (nread == 0) { + THROW(EndOfStreamException, "No data beyond " << to); + } else { + break; + } + } + + if (offset == 0) { + // generate new packet + factory.makePacket(packet, current, boardNr); + current += packet.header.nrBlocks; + } + + size_t pktSize = packet.packetSize(); + size_t numBytes = std::min(pktSize - offset, iov[i].iov_len); + memcpy(iov[i].iov_base, reinterpret_cast<char*>(&packet) + offset, numBytes); + + offset += numBytes; + if (offset == pktSize) { + // written full packet, so we'll need a new one on next read + offset = 0; + } + + nread += numBytes; + + // Mimic tryRead() impl above: max 1 (partial) packet per buffer. + // Then we can only use the next iov if we could exactly fill the previous, else our retval is ambiguous. + if (numBytes < pktSize) { + break; + } + } + + return nread; + } + + virtual size_t tryWritev(const struct iovec * /*iov*/, int /*iovcnt*/) + { + THROW(NotImplemented, "Writing to PacketStream is not supported"); } private: diff --git a/RTCP/Cobalt/InputProc/src/Station/filterRSP.cc b/RTCP/Cobalt/InputProc/src/Station/filterRSP.cc index 80dacfdf124..a08a7c694b8 100644 --- a/RTCP/Cobalt/InputProc/src/Station/filterRSP.cc +++ b/RTCP/Cobalt/InputProc/src/Station/filterRSP.cc @@ -33,7 +33,7 @@ #include <Stream/StreamFactory.h> #include <ApplCommon/PosixTime.h> #include <CoInterface/SmartPtr.h> -#include "RSP.h" +#include <CoInterface/RSP.h> #include "PacketReader.h" using namespace LOFAR; diff --git a/RTCP/Cobalt/InputProc/src/Station/generateRSP.cc b/RTCP/Cobalt/InputProc/src/Station/generateRSP.cc index 26c453f790e..a22df4b097f 100644 --- a/RTCP/Cobalt/InputProc/src/Station/generateRSP.cc +++ b/RTCP/Cobalt/InputProc/src/Station/generateRSP.cc @@ -33,9 +33,9 @@ #include <ApplCommon/PosixTime.h> #include <Stream/StreamFactory.h> #include <CoInterface/SmartPtr.h> +#include <CoInterface/RSP.h> #include <InputProc/Buffer/BoardMode.h> #include <InputProc/RSPTimeStamp.h> -#include <InputProc/Station/RSP.h> #include <InputProc/Station/RSPPacketFactory.h> using namespace std; diff --git a/RTCP/Cobalt/InputProc/src/Station/printRSP.cc b/RTCP/Cobalt/InputProc/src/Station/printRSP.cc index 4ad2daeddcc..1cecf4aabef 100644 --- a/RTCP/Cobalt/InputProc/src/Station/printRSP.cc +++ b/RTCP/Cobalt/InputProc/src/Station/printRSP.cc @@ -21,8 +21,6 @@ //# Always #include <lofar_config.h> first! #include <lofar_config.h> -#include "RSP.h" - #include <ctime> #include <cstring> #include <cstdlib> @@ -33,6 +31,7 @@ #include <Common/LofarLogger.h> #include <Common/DataConvert.h> #include <Stream/FileStream.h> +#include <CoInterface/RSP.h> #include <InputProc/RSPTimeStamp.h> using namespace LOFAR; diff --git a/RTCP/Cobalt/InputProc/src/Station/repairRSP.cc b/RTCP/Cobalt/InputProc/src/Station/repairRSP.cc index d45caa76b51..26c5d28e608 100644 --- a/RTCP/Cobalt/InputProc/src/Station/repairRSP.cc +++ b/RTCP/Cobalt/InputProc/src/Station/repairRSP.cc @@ -33,7 +33,7 @@ #include <ApplCommon/PosixTime.h> #include <Stream/StreamFactory.h> #include <CoInterface/SmartPtr.h> -#include "RSP.h" +#include <CoInterface/RSP.h> #include "PacketReader.h" using namespace LOFAR; diff --git a/RTCP/Cobalt/InputProc/test/tPacketReader.cc b/RTCP/Cobalt/InputProc/test/tPacketReader.cc index a689800de0a..3f5676bcdea 100644 --- a/RTCP/Cobalt/InputProc/test/tPacketReader.cc +++ b/RTCP/Cobalt/InputProc/test/tPacketReader.cc @@ -25,8 +25,8 @@ #include <Common/LofarLogger.h> #include <Stream/FileStream.h> +#include <CoInterface/RSP.h> #include <InputProc/Station/PacketReader.h> -#include <InputProc/Station/RSP.h> using namespace LOFAR; using namespace Cobalt; diff --git a/RTCP/Cobalt/InputProc/test/tRSP.cc b/RTCP/Cobalt/InputProc/test/tRSP.cc index 9c7ade0a028..91a68fefd4f 100644 --- a/RTCP/Cobalt/InputProc/test/tRSP.cc +++ b/RTCP/Cobalt/InputProc/test/tRSP.cc @@ -28,8 +28,8 @@ #include <Common/DataConvert.h> #include <Stream/FileStream.h> +#include <CoInterface/RSP.h> #include <InputProc/RSPTimeStamp.h> -#include <InputProc/Station/RSP.h> using namespace LOFAR; diff --git a/RTCP/Cobalt/OutputProc/src/CMakeLists.txt b/RTCP/Cobalt/OutputProc/src/CMakeLists.txt index 1646bd68ba4..656663906c0 100644 --- a/RTCP/Cobalt/OutputProc/src/CMakeLists.txt +++ b/RTCP/Cobalt/OutputProc/src/CMakeLists.txt @@ -23,6 +23,7 @@ lofar_add_library(outputproc CommonLofarAttributes.cc OutputThread.cc SubbandWriter.cc + RSPRawWriter.cc TBB_StaticMapping.cc ) diff --git a/RTCP/Cobalt/OutputProc/src/CommonLofarAttributes.cc b/RTCP/Cobalt/OutputProc/src/CommonLofarAttributes.cc index 1c1d9832a7a..51b0c229835 100644 --- a/RTCP/Cobalt/OutputProc/src/CommonLofarAttributes.cc +++ b/RTCP/Cobalt/OutputProc/src/CommonLofarAttributes.cc @@ -135,7 +135,7 @@ namespace LOFAR } // max freq is shifted if 2nd PPF is active for all types in obs // min freq is shifted if 2nd PPF is active for any type in obs - bool applyPPFtoMax = nrAppliedPPFs == parset.nrObsOutputTypes(); + bool applyPPFtoMax = nrAppliedPPFs == parset.nrProcessedOutputTypes(); bool applyPPFtoMin = nrAppliedPPFs > 0; vector<double> subbandCenterFrequencies(parset.settings.subbands.size()); diff --git a/RTCP/Cobalt/OutputProc/src/GPUProcIO.cc b/RTCP/Cobalt/OutputProc/src/GPUProcIO.cc index 649be8f7002..330ab5abb29 100644 --- a/RTCP/Cobalt/OutputProc/src/GPUProcIO.cc +++ b/RTCP/Cobalt/OutputProc/src/GPUProcIO.cc @@ -1,5 +1,6 @@ //# GPUProcIO.cc: Routines for communicating with GPUProc -//# Copyright (C) 2008-2014 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2008-2014, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -51,6 +52,7 @@ #include <CoInterface/SmartPtr.h> #include <CoInterface/SelfDestructTimer.h> #include "SubbandWriter.h" +#include "RSPRawWriter.h" #include "OutputThread.h" using namespace LOFAR; @@ -154,6 +156,7 @@ bool process(Stream &controlStream) vector<SmartPtr<SubbandWriter> > subbandWriters; vector<SmartPtr<TABOutputThread> > tabWriters; + vector<SmartPtr<RSPRawWriter> > rspRawWriters; /* * Construct writers @@ -198,7 +201,7 @@ bool process(Stream &controlStream) continue; } - const unsigned allFileIdx = fileIdx + parset.settings.correlator.files.size(); + const unsigned allFileIdx = fileIdx + (parset.settings.correlator.enabled ? parset.settings.correlator.files.size() : 0); mdLogger.log(mdKeyPrefix + PN_COP_STORAGE_HOST + '[' + lexical_cast<string>(allFileIdx) + ']', myHostName); LOG_INFO_STR("Allocating transpose buffers for " << file.location.filename); @@ -244,6 +247,34 @@ bool process(Stream &controlStream) } } + if (parset.settings.rspRaw.enabled) { + for (size_t fileIdx = 0; fileIdx < parset.settings.rspRaw.files.size(); ++fileIdx) + { + struct ObservationSettings::RSPRaw::File &file = parset.settings.rspRaw.files[fileIdx]; + + if (myHostNames.find(file.location.host) == myHostNames.end()) { + continue; + } + + LOG_INFO_STR("starting with RSP raw fileIdx " << fileIdx); + + // The rest of the system doesn't know about RSP raw data output, but if monitoring did, enable this: + /* + const unsigned allFileIdx = fileIdx + (parset.settings.correlator.enabled ? parset.settings.correlator.files.size() : 0) + + (parset.settings.beamFormer.enabled ? parset.settings.beamFormer.files.size() : 0); + mdLogger.log(mdKeyPrefix + PN_COP_STORAGE_HOST + '[' + lexical_cast<string>(allFileIdx) + ']', myHostName); + */ + + string logPrefix = str(format("[obs %u RSP raw stream %3u] ") + % parset.settings.observationID % fileIdx); + + RSPRawWriter *writer = new RSPRawWriter(parset, fileIdx, mdLogger, mdKeyPrefix, logPrefix); + rspRawWriters.push_back(writer); + + LOG_INFO_STR("done with RSP raw fileIdx " << fileIdx); + } + } + LOG_INFO_STR("Finished setting up writers"); /* @@ -256,7 +287,7 @@ bool process(Stream &controlStream) TABTranspose::MultiReceiver mr("2nd-transpose-", collectors); -# pragma omp parallel sections num_threads(3) +# pragma omp parallel sections num_threads(4) { // Done signal from controller, by sending the final meta data # pragma omp section @@ -312,6 +343,18 @@ bool process(Stream &controlStream) tabWriters[i]->process(); } } + + // RSPRawWriters +# pragma omp section + { + OMPThread::ScopedName sn("rspRawWr"); + +# pragma omp parallel for num_threads(rspRawWriters.size()) + for (int i = 0; i < (int)rspRawWriters.size(); ++i) { + OMPThread::ScopedName sn(str(format("rspRawWr %u") % rspRawWriters[i]->streamNr())); + rspRawWriters[i]->process(); + } + } } /* @@ -361,6 +404,21 @@ bool process(Stream &controlStream) bus.send(msg); } + // The rest of the system doesn't know about RSP raw data output, but if feedback did, enable this: + /* + for (size_t i = 0; i < rspRawWriters.size(); ++i) { + Protocols::TaskFeedbackDataproducts msg( + myName, + "", + str(boost::format("Feedback for RSP Raw Data, file nr %s") % rspRawWriters[i]->streamNr()), + str(format("%s") % parset.settings.momID), + str(format("%s") % parset.settings.observationID), + rspRawWriters[i]->feedbackLTA()); + + bus.send(msg); + } + */ + /* * SIGN OFF */ diff --git a/RTCP/Cobalt/OutputProc/src/GPUProcIO.h b/RTCP/Cobalt/OutputProc/src/GPUProcIO.h index ba1ec282829..dbab9c828e5 100644 --- a/RTCP/Cobalt/OutputProc/src/GPUProcIO.h +++ b/RTCP/Cobalt/OutputProc/src/GPUProcIO.h @@ -1,5 +1,6 @@ //# GPUProcIO.h -//# Copyright (C) 2009-2014 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2009-2014, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -34,7 +35,7 @@ namespace LOFAR // Receive and process a full observation. Will: // * Receive a Parset over the controlStream // * Fulfill roles for parset.settings.outputProcHosts[myRank]: - // - Start SubbandWriters/TABWriters + // - Start SubbandWriters/TABWriters/RSPRawWriters // - Receive input and write output for all of them // * Call readFinalMetaData to obtain the final metadata from GPUProc, // and send it to all writers. diff --git a/RTCP/Cobalt/OutputProc/src/InputThread.cc b/RTCP/Cobalt/OutputProc/src/InputThread.cc index d53c81bac9d..b9cd5d40fab 100644 --- a/RTCP/Cobalt/OutputProc/src/InputThread.cc +++ b/RTCP/Cobalt/OutputProc/src/InputThread.cc @@ -1,5 +1,6 @@ //# InputThread.cc -//# Copyright (C) 2008-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2008-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -34,18 +35,19 @@ namespace LOFAR { namespace Cobalt { - InputThread::InputThread(const Parset &parset, + InputThread::InputThread(const Parset &parset, OutputType outputType, unsigned streamNr, Pool<StreamableData> &outputPool, const std::string &logPrefix) : itsLogPrefix(logPrefix + "[InputThread] "), itsNrIntegrationsReceived(0), itsNrIntegrations(parset.settings.correlator.nrIntegrations), - itsInputDescriptor(getStreamDescriptorBetweenIONandStorage(parset, CORRELATED_DATA, streamNr)), + itsInputDescriptor(getStreamDescriptorBetweenIONandStorage(parset, outputType, streamNr)), itsOutputPool(outputPool), itsDeadline(parset.settings.realTime ? parset.settings.stopTime : 0) { - ASSERT(parset.settings.correlator.enabled); + ASSERT((parset.settings.correlator.enabled && outputType == CORRELATED_DATA) || + (parset.settings.rspRaw.enabled && outputType == RSP_RAW_DATA)); } @@ -57,10 +59,10 @@ namespace LOFAR LOG_INFO_STR(itsLogPrefix << "Creating connection from " << itsInputDescriptor << ": done" ); for(SmartPtr<StreamableData> data; (data = itsOutputPool.free.remove()) != NULL; itsOutputPool.filled.append(data)) { - data->read(streamFromION, true, 1); // Cobalt writes with an alignment of 1 + data->read(streamFromION, 1); // Cobalt writes with an alignment of 1 ++itsNrIntegrationsReceived; - LOG_DEBUG_STR(itsLogPrefix << "Received integration " << data->sequenceNumber()); + LOG_DEBUG_STR(itsLogPrefix << "Received data block with seq nr " << data->sequenceNumber()); } } catch (TimeOutException &) { LOG_WARN_STR(itsLogPrefix << "Connection from " << itsInputDescriptor << " timed out"); diff --git a/RTCP/Cobalt/OutputProc/src/InputThread.h b/RTCP/Cobalt/OutputProc/src/InputThread.h index 85b561240d4..515aa20dcf8 100644 --- a/RTCP/Cobalt/OutputProc/src/InputThread.h +++ b/RTCP/Cobalt/OutputProc/src/InputThread.h @@ -1,5 +1,6 @@ //# InputThread.h -//# Copyright (C) 2008-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2008-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -28,6 +29,7 @@ #include <CoInterface/Parset.h> #include <CoInterface/Pool.h> #include <CoInterface/StreamableData.h> +#include <CoInterface/OutputTypes.h> namespace LOFAR @@ -42,12 +44,13 @@ namespace LOFAR * The Stream is created from the parset through using * getStreamDescriptorBetweenIONandStorage. * - * This class is designed to handle visibilities only. + * This class is designed to handle visibility (UV) and RSP raw data. */ class InputThread { public: InputThread(const Parset &parset, + OutputType outputType, unsigned streamNr, Pool<StreamableData> &outputPool, const std::string &logPrefix); @@ -57,7 +60,8 @@ namespace LOFAR private: const std::string itsLogPrefix; - // we receive integration "blocks" + // We receive integration "blocks" (UV); + // for RSP raw it is a stream of (up to) some block size bytes. size_t itsNrIntegrationsReceived; const size_t itsNrIntegrations; diff --git a/RTCP/Cobalt/OutputProc/src/MSWriterFile.cc b/RTCP/Cobalt/OutputProc/src/MSWriterFile.cc index ebbea6c74b6..e789a08069c 100644 --- a/RTCP/Cobalt/OutputProc/src/MSWriterFile.cc +++ b/RTCP/Cobalt/OutputProc/src/MSWriterFile.cc @@ -1,5 +1,6 @@ //# MSWriterFile.cc: a raw file writer -//# Copyright (C) 2009-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2009-2013, 2016 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -90,7 +91,7 @@ namespace LOFAR void MSWriterFile::write(StreamableData *data) { - data->write(&itsFile, true, 512); + data->write(&itsFile, 512); } diff --git a/RTCP/Cobalt/OutputProc/src/MSWriterNull.cc b/RTCP/Cobalt/OutputProc/src/MSWriterNull.cc index 4260d4c06a8..f1043edc4e5 100644 --- a/RTCP/Cobalt/OutputProc/src/MSWriterNull.cc +++ b/RTCP/Cobalt/OutputProc/src/MSWriterNull.cc @@ -51,7 +51,7 @@ namespace LOFAR void MSWriterNull::write(StreamableData *data) { - // We do not know why the creation of the propper writer failed. + // We do not know why the creation of the proper writer failed. // Assume nothing and only report that we did not write anything itsConfiguration.replace("percentageWritten", str(format("%u") % 0)); itsConfiguration.replace("size", str(format("%u") % getDataSize())); diff --git a/RTCP/Cobalt/OutputProc/src/OutputThread.cc b/RTCP/Cobalt/OutputProc/src/OutputThread.cc index 5dc58114d21..0b96d5a7e29 100644 --- a/RTCP/Cobalt/OutputProc/src/OutputThread.cc +++ b/RTCP/Cobalt/OutputProc/src/OutputThread.cc @@ -1,5 +1,6 @@ //# OutputThread.cc: -//# Copyright (C) 2009-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2009-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -33,6 +34,7 @@ #include <Common/Thread/Cancellation.h> #include <ApplCommon/PVSSDatapointDefs.h> +#include <CoInterface/Parset.h> #include <CoInterface/OutputTypes.h> #include <CoInterface/Exceptions.h> #include <CoInterface/LTAFeedback.h> @@ -248,7 +250,9 @@ namespace LOFAR } # pragma omp section - init(); + { + init(); + } } } @@ -287,33 +291,27 @@ namespace LOFAR const std::string fileName = itsParset.getFileName(CORRELATED_DATA, itsStreamNr); const std::string path = directoryName + "/" + fileName; + LOG_INFO_STR(itsLogPrefix << "Writing correlated data to " << path); - try - { - LOG_INFO_STR(itsLogPrefix << "Writing to " << path); - - itsWriter = new MSWriterCorrelated(itsLogPrefix, path, itsParset, itsStreamNr); + if (itsParset.settings.realTime) { + try { + itsWriter = new MSWriterCorrelated(itsLogPrefix, path, itsParset, itsStreamNr); - logInitialStreamMetadataEvents("Correlated", fileName, directoryName); - } - catch (Exception &ex) - { - LOG_ERROR_STR(itsLogPrefix << "Cannot open " << path << ": " << ex); - if (!itsParset.settings.realTime) - THROW(StorageException, ex); + logInitialStreamMetadataEvents("Correlated", fileName, directoryName); + } catch (Exception &ex) { + LOG_ERROR_STR(itsLogPrefix << "Cannot open " << path << ": " << ex); + itsWriter = new MSWriterNull(itsParset); - itsWriter = new MSWriterNull(itsParset); #if defined HAVE_AIPSPP - } - catch (casa::AipsError &ex) - { - LOG_ERROR_STR(itsLogPrefix << "Caught AipsError: " << ex.what()); - - if (!itsParset.settings.realTime) - THROW(StorageException, ex.what()); - - itsWriter = new MSWriterNull(itsParset); + } catch (casa::AipsError &ex) { + LOG_ERROR_STR(itsLogPrefix << "Caught AipsError: " << ex.what()); + itsWriter = new MSWriterNull(itsParset); #endif + } + } else { // don't handle exception in non-RT: it is fatal: avoid rethrow for a clean stracktrace + itsWriter = new MSWriterCorrelated(itsLogPrefix, path, itsParset, itsStreamNr); + + logInitialStreamMetadataEvents("Correlated", fileName, directoryName); } itsNrExpectedBlocks = itsParset.settings.correlator.nrIntegrations; @@ -351,39 +349,98 @@ namespace LOFAR const std::string fileName = itsParset.getFileName(BEAM_FORMED_DATA, itsStreamNr); const std::string path = directoryName + "/" + fileName; + LOG_INFO_STR(itsLogPrefix << "Writing beamformed data to " << path); - try - { - LOG_INFO_STR(itsLogPrefix << "Writing to " << path); + if (itsParset.settings.realTime) { + try { +#ifdef HAVE_DAL + itsWriter = new MSWriterDAL<float,3>(path, itsParset, itsStreamNr); +#else + itsWriter = new MSWriterFile(path); +#endif + logInitialStreamMetadataEvents("Beamformed", fileName, directoryName); + } catch (Exception &ex) { + LOG_ERROR_STR(itsLogPrefix << "Cannot open " << path << ": " << ex); + itsWriter = new MSWriterNull(itsParset); + +#if defined HAVE_AIPSPP + } catch (casa::AipsError &ex) { + LOG_ERROR_STR(itsLogPrefix << "Caught AipsError: " << ex.what()); + itsWriter = new MSWriterNull(itsParset); +#endif + } + } else { // don't handle exception in non-RT: it is fatal: avoid rethrow for a clean stracktrace #ifdef HAVE_DAL itsWriter = new MSWriterDAL<float,3>(path, itsParset, itsStreamNr); #else itsWriter = new MSWriterFile(path); #endif - logInitialStreamMetadataEvents("Beamformed", fileName, directoryName); } - catch (Exception &ex) - { - LOG_ERROR_STR(itsLogPrefix << "Cannot open " << path << ": " << ex); - if (!itsParset.settings.realTime) - THROW(StorageException, ex); - itsWriter = new MSWriterNull(itsParset); -#if defined HAVE_AIPSPP - } - catch (casa::AipsError &ex) - { - LOG_ERROR_STR(itsLogPrefix << "Caught AipsError: " << ex.what()); - if ( !itsParset.settings.realTime) - THROW(StorageException, ex.what()); + itsNrExpectedBlocks = itsParset.settings.nrBlocks(); + } - itsWriter = new MSWriterNull(itsParset); -#endif + + RSPRawOutputThread::RSPRawOutputThread(const Parset &parset, + unsigned streamNr, Pool<StreamableData> &outputPool, + RTmetadata &mdLogger, const std::string &mdKeyPrefix, + const std::string &logPrefix, const std::string &targetDirectory) + : + OutputThread<StreamableData>( + parset, + streamNr, + outputPool, + mdLogger, + mdKeyPrefix, + logPrefix + "[RSPRawOutputThread] ", + targetDirectory) + { + } + + void RSPRawOutputThread::createMS() + { + // Unlike the other output types, there is no need to grab casacoreMutex + // or delay cancellation, because the RSP raw writer does not use casacore or libhdf5. + + const std::string directoryName = + itsTargetDirectory == "" + ? itsParset.getDirectoryName(RSP_RAW_DATA, itsStreamNr) + : itsTargetDirectory; + const std::string fileName = itsParset.getFileName(CORRELATED_DATA, itsStreamNr); + + const std::string path = directoryName + "/" + fileName; + LOG_INFO_STR(itsLogPrefix << "Writing RSP raw data to " << path); + + // Write parset as observation metadata. We end up with many duplicates, but at least we know all storage nodes used have it. + // Also patch antenna field stream locations (originals in StationStreams.parset) for easy offline reprocessing. + Parset rspRawParset = itsParset; +//TODO: patch locations, like +//PIC.Core.CS006HBA.RSP.ports = [udp:cbt004-10GB01:10060, udp:cbt004-10GB01:10061, udp:cbt004-10GB01:10062, udp:cbt004-10GB01:10063] +//PIC.Core.CS006HBA.RSP.receiver = cbt004_0 + + if (itsParset.settings.realTime) { + try { + rspRawParset.writeFile(fileName + ".parset"); + itsWriter = new MSWriterFile(path); + + // The rest of the system doesn't know about RSP raw data output, but if monitoring did, enable this: + //logInitialStreamMetadataEvents("RSPRaw", fileName, directoryName); + } catch (Exception& ex) { + LOG_ERROR_STR(itsLogPrefix << "Cannot open " << path << ": " << ex); + itsWriter = new MSWriterNull(itsParset); + } + } else { // don't handle exception in non-RT: it is fatal: avoid rethrow for a clean stracktrace + rspRawParset.writeFile(fileName + ".parset"); + itsWriter = new MSWriterFile(path); + + // The rest of the system doesn't know about RSP raw data output, but if monitoring did, enable this: + //logInitialStreamMetadataEvents("RSPRaw", fileName, directoryName); } - itsNrExpectedBlocks = itsParset.settings.nrBlocks(); +//TODO: see if we can get the data dropping stats in a useful state for RSP raw + itsNrExpectedBlocks = itsParset.settings.nrBlocks() * itsParset.settings.blockSize; } } // namespace Cobalt } // namespace LOFAR diff --git a/RTCP/Cobalt/OutputProc/src/OutputThread.h b/RTCP/Cobalt/OutputProc/src/OutputThread.h index b272680ba0c..93e8395960b 100644 --- a/RTCP/Cobalt/OutputProc/src/OutputThread.h +++ b/RTCP/Cobalt/OutputProc/src/OutputThread.h @@ -1,5 +1,6 @@ //# OutputThread.h -//# Copyright (C) 2009-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# Copyright (C) 2009-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -140,6 +141,22 @@ namespace LOFAR }; + /* + * RSPRawOutputThread specialises in creating *_rsp.raw + * files for raw RSP antenna field data. + */ + class RSPRawOutputThread: public OutputThread<StreamableData> + { + public: + RSPRawOutputThread(const Parset &parset, unsigned streamNr, + Pool<StreamableData> &outputPool, + RTmetadata &mdLogger, const std::string &mdKeyPrefix, + const std::string &logPrefix, + const std::string &targetDirectory = ""); + + virtual void createMS(); + }; + } // namespace Cobalt } // namespace LOFAR diff --git a/RTCP/Cobalt/OutputProc/src/RSPRawWriter.cc b/RTCP/Cobalt/OutputProc/src/RSPRawWriter.cc new file mode 100644 index 00000000000..b42aeec6273 --- /dev/null +++ b/RTCP/Cobalt/OutputProc/src/RSPRawWriter.cc @@ -0,0 +1,93 @@ +//# RSPRawWriter.cc: Write raw data stream of an RSP board to storage +//# Copyright (C) 2017 ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#include <lofar_config.h> + +#include "RSPRawWriter.h" + +//#include <CoInterface/CorrelatedData.h> +#include <CoInterface/OMPThread.h> +#include <Common/Timer.h> + +#include <boost/format.hpp> +using boost::format; + +namespace LOFAR +{ + namespace Cobalt + { + RSPRawWriter::RSPRawWriter(const Parset &parset, unsigned streamNr, + RTmetadata &mdLogger, const std::string &mdKeyPrefix, + const std::string &logPrefix) + : + itsStreamNr(streamNr), + itsOutputPool(str(format("RSPRawWriter::itsOutputPool [stream %u]") % streamNr), parset.settings.realTime), + itsInputThread(parset, RSP_RAW_DATA, streamNr, itsOutputPool, logPrefix), + itsOutputThread(parset, streamNr, itsOutputPool, mdLogger, mdKeyPrefix, logPrefix) + { + NSTimer timer(str(format("preallocator %u") % itsStreamNr), true, true); + + for (unsigned i = 0; i < preAllocateReceiveQueue; i++) { + timer.start(); + + LOG_DEBUG_STR(str(format("[stream %u] Allocating element %u") % itsStreamNr % i)); + RSPRawData *data = new RSPRawData(); + LOG_DEBUG_STR(str(format("[stream %u] Appending element %u") % itsStreamNr % i)); + itsOutputPool.free.append(data); + + timer.stop(); + } + } + + + void RSPRawWriter::process() + { +# pragma omp parallel sections num_threads(2) + { +# pragma omp section + { + OMPThread::ScopedName sn(str(format("RSPRaw input %u") % itsStreamNr)); + + itsInputThread.process(); + } + +# pragma omp section + { + OMPThread::ScopedName sn(str(format("RSPRaw output %u") % itsStreamNr)); + + itsOutputThread.process(); + } + } + } + + + void RSPRawWriter::fini( const FinalMetaData &finalMetaData ) + { + itsOutputThread.fini(finalMetaData); + } + + + ParameterSet RSPRawWriter::feedbackLTA() const + { + return itsOutputThread.feedbackLTA(); + } + } // namespace Cobalt +} // namespace LOFAR + diff --git a/RTCP/Cobalt/OutputProc/src/RSPRawWriter.h b/RTCP/Cobalt/OutputProc/src/RSPRawWriter.h new file mode 100644 index 00000000000..2f1b45245d0 --- /dev/null +++ b/RTCP/Cobalt/OutputProc/src/RSPRawWriter.h @@ -0,0 +1,75 @@ +//# RSPRawWriter.h: Write raw data stream of an RSP board to storage +//# Copyright (C) 2017 ASTRON (Netherlands Institute for Radio Astronomy) +//# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands +//# +//# This file is part of the LOFAR software suite. +//# The LOFAR software suite is free software: you can redistribute it and/or +//# modify it under the terms of the GNU General Public License as published +//# by the Free Software Foundation, either version 3 of the License, or +//# (at your option) any later version. +//# +//# The LOFAR software suite is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License along +//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. +//# +//# $Id$ + +#ifndef LOFAR_STORAGE_RSPBOARDWRITER_H +#define LOFAR_STORAGE_RSPBOARDWRITER_H + +#include <string> + +#include <CoInterface/Parset.h> +#include <CoInterface/Pool.h> +#include <CoInterface/StreamableData.h> +#include <CoInterface/FinalMetaData.h> +#include "InputThread.h" +#include "OutputThread.h" + +namespace LOFAR +{ + namespace Cobalt + { + /* + * RSPRawWriter is responsible for completely handling the reception + * and writing of one stream of data from an RSP board (via InputProc/GPUProc). + * + * It maintains an InputThread and RSPRawOutputThread, connected by + * an internal Pool<> of data blocks. + */ + class RSPRawWriter + { + public: + RSPRawWriter(const Parset &parset, + unsigned streamNr, + RTmetadata &mdLogger, + const std::string &mdKeyPrefix, + const std::string &logPrefix); + + void process(); + + void fini(const FinalMetaData &finalMetaData); + + ParameterSet feedbackLTA() const; + + unsigned streamNr() const { return itsStreamNr; } + + private: + static const unsigned preAllocateReceiveQueue = 32; // number of elements to construct before starting + + const unsigned itsStreamNr; + + Pool<StreamableData> itsOutputPool; + + InputThread itsInputThread; + RSPRawOutputThread itsOutputThread; + }; + } // namespace Cobalt +} // namespace LOFAR + +#endif + diff --git a/RTCP/Cobalt/OutputProc/src/SubbandWriter.cc b/RTCP/Cobalt/OutputProc/src/SubbandWriter.cc index 20a616788a3..10e20410033 100644 --- a/RTCP/Cobalt/OutputProc/src/SubbandWriter.cc +++ b/RTCP/Cobalt/OutputProc/src/SubbandWriter.cc @@ -1,5 +1,6 @@ -//# SubbandWriter.cc: Writes visibilities and beam-formed data -//# Copyright (C) 2008-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# SubbandWriter.cc: Write a subband of visibility data (UV) to storage +//# Copyright (C) 2008-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -42,7 +43,7 @@ namespace LOFAR itsArena(0), itsAllocator(0), itsOutputPool(str(format("SubbandWriter::itsOutputPool [stream %u]") % streamNr), parset.settings.realTime), - itsInputThread(parset, streamNr, itsOutputPool, logPrefix), + itsInputThread(parset, CORRELATED_DATA, streamNr, itsOutputPool, logPrefix), itsOutputThread(parset, streamNr, itsOutputPool, mdLogger, mdKeyPrefix, logPrefix), itsAlignment(512), itsNrStations(parset.settings.correlator.stations.size()), @@ -94,14 +95,14 @@ namespace LOFAR # pragma omp section { - OMPThread::ScopedName sn(str(format("input %u") % itsStreamNr)); + OMPThread::ScopedName sn(str(format("uv input %u") % itsStreamNr)); itsInputThread.process(); } # pragma omp section { - OMPThread::ScopedName sn(str(format("output %u") % itsStreamNr)); + OMPThread::ScopedName sn(str(format("uv output %u") % itsStreamNr)); itsOutputThread.process(); } diff --git a/RTCP/Cobalt/OutputProc/src/SubbandWriter.h b/RTCP/Cobalt/OutputProc/src/SubbandWriter.h index 10eaa727098..9127148ec04 100644 --- a/RTCP/Cobalt/OutputProc/src/SubbandWriter.h +++ b/RTCP/Cobalt/OutputProc/src/SubbandWriter.h @@ -1,5 +1,6 @@ -//# SubbandWriter.h: Write visibilites and beam-formed data -//# Copyright (C) 2008-2013 ASTRON (Netherlands Institute for Radio Astronomy) +//# SubbandWriter.h: Write a subband of visibility data (UV) to storage +//# Copyright (C) 2008-2013, 2017 +//# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands //# //# This file is part of the LOFAR software suite. @@ -23,7 +24,6 @@ #include <string> -#include <CoInterface/OutputTypes.h> #include <CoInterface/Parset.h> #include <CoInterface/Pool.h> #include <CoInterface/Allocator.h> diff --git a/RTCP/Cobalt/OutputProc/src/plotMS.cc b/RTCP/Cobalt/OutputProc/src/plotMS.cc index e98d90c5cde..ca1e47ceebd 100644 --- a/RTCP/Cobalt/OutputProc/src/plotMS.cc +++ b/RTCP/Cobalt/OutputProc/src/plotMS.cc @@ -186,7 +186,7 @@ int main(int argc, char *argv[]) for(;; ) { try { - data->read(&datafile, true, 512); + data->read(&datafile, 512); } catch (EndOfStreamException &) { break; } diff --git a/RTCP/Cobalt/OutputProc/test/tSubbandWriter.cc b/RTCP/Cobalt/OutputProc/test/tSubbandWriter.cc index d51f882ab71..23afabfd4e9 100644 --- a/RTCP/Cobalt/OutputProc/test/tSubbandWriter.cc +++ b/RTCP/Cobalt/OutputProc/test/tSubbandWriter.cc @@ -118,7 +118,7 @@ SUITE(SubbandWriter) *(data.visibilities.origin() + i) = complex<float>(i, 2*i); } - data.write(inputStream, true, 1); + data.write(inputStream, 1); } } @@ -128,7 +128,7 @@ SUITE(SubbandWriter) CorrelatedData data(ps.nrMergedStations(), ps.settings.correlator.nrChannels, ps.settings.correlator.nrSamplesPerIntegration(), heapAllocator, 512); - data.read(&f, true, 512); + data.read(&f, 512); for (size_t i = 0; i < data.visibilities.num_elements(); ++i) { CHECK_EQUAL(complex<float>(i, 2*i), *(data.visibilities.origin() + i)); -- GitLab