32#include <sys/socket.h>
34#define BEGIN_NAMESPACE_ROOFIT namespace RooFit {
35#define END_NAMESPACE_ROOFIT }
40namespace BidirMMapPipe_impl {
56 int (*
f)(
int,
char*, std::size_t))
57 {
return f(err, buf, sz); }
59 static int dostrerror_r(
int,
char*, std::size_t,
60 char* (*
f)(
int,
char*, std::size_t));
65 virtual const char*
what() const noexcept {
return m_buf; }
68 BidirMMapPipeException::BidirMMapPipeException(
const char* msg,
int err)
70 std::size_t msgsz = std::strlen(msg);
72 msgsz = std::min(msgsz, std::size_t(s_sz));
73 std::copy(msg, msg + msgsz, m_buf);
74 if (msgsz < s_sz) { m_buf[msgsz] =
':'; ++msgsz; }
75 if (msgsz < s_sz) { m_buf[msgsz] =
' '; ++msgsz; }
80 dostrerror_r(err, &m_buf[msgsz], s_sz - msgsz, ::strerror_r);
85 int BidirMMapPipeException::dostrerror_r(
int err,
char* buf,
86 std::size_t sz,
char* (*
f)(
int,
char*, std::size_t))
89 char *tmp =
f(err, buf, sz);
90 if (tmp && tmp != buf) {
91 std::strncpy(buf, tmp, sz);
93 if (std::strlen(tmp) > sz - 1)
return ERANGE;
121 Page() : m_next(0), m_size(0), m_pos(0)
125 assert(std::numeric_limits<unsigned short>::max() >=
126 PageChunk::pagesize());
129 void setNext(
const Page*
p);
133 unsigned short&
size() {
return m_size; }
135 unsigned size()
const {
return m_size; }
137 unsigned short&
pos() {
return m_pos; }
139 unsigned pos()
const {
return m_pos; }
142 {
return reinterpret_cast<unsigned char*
>(
const_cast<Page*
>(
this))
145 inline unsigned char*
end()
const
146 {
return reinterpret_cast<unsigned char*
>(
const_cast<Page*
>(
this))
147 + PageChunk::pagesize(); }
150 {
return PageChunk::pagesize() -
sizeof(
Page); }
152 bool empty()
const {
return !m_size; }
156 unsigned free()
const {
return capacity() - m_size; }
168 const char* p1 =
reinterpret_cast<char*
>(
this);
169 const char* p2 =
reinterpret_cast<const char*
>(
p);
170 std::ptrdiff_t tmp = p2 - p1;
172 assert(!(tmp % PageChunk::pagesize()));
173 tmp /=
static_cast<std::ptrdiff_t
>(PageChunk::pagesize());
176 assert(m_next == tmp);
184 if (!m_next)
return 0;
185 char* ptmp =
reinterpret_cast<char*
>(
const_cast<Page*
>(
this));
186 ptmp += std::ptrdiff_t(m_next) * PageChunk::pagesize();
187 return reinterpret_cast<Page*
>(ptmp);
234 static unsigned pagesize() {
return PageChunk::pagesize(); }
237 {
return PageChunk::mmapVariety(); }
251 unsigned m_szmap[(maxsz - minsz) / szincr];
258 void updateCurSz(
int sz,
int incr);
260 int nextChunkSz()
const;
262 void putOnFreeList(
Chunk* chunk);
264 void release(
Chunk* chunk);
292 m_pimpl(other.m_pimpl)
297 if (&other ==
this)
return *
this;
311 assert(pgno < m_pimpl->m_npages);
312 unsigned char* pptr =
315 return reinterpret_cast<Page*
>(pptr);
320 const unsigned char* pptr =
321 reinterpret_cast<const unsigned char*
>(
p);
322 const unsigned char* bptr =
324 assert(0 == ((pptr - bptr) %
pagesize()));
325 const unsigned nr = (pptr - bptr) /
pagesize();
326 assert(nr < m_pimpl->m_npages);
333 long pgsz = sysconf(_SC_PAGESIZE);
334 if (-1 == pgsz)
throw Exception(
"sysconf", errno);
335 if (pgsz > 512 && pgsz >
long(
sizeof(
Page)))
345 unsigned length,
unsigned nPgPerGroup) :
347 m_end(reinterpret_cast<void*>(
348 reinterpret_cast<unsigned char*>(m_begin) +
length)),
349 m_parent(parent), m_nPgPerGrp(nPgPerGroup), m_nUsedGrp(0)
352 unsigned char*
p =
reinterpret_cast<unsigned char*
>(
m_begin);
353 unsigned char* pend =
reinterpret_cast<unsigned char*
>(
m_end);
367 {
return p.m_pimpl->m_parent ==
this; }
382 m_freelist.push_front(
reinterpret_cast<void*
>(
p[0u]));
406 static bool msgprinted =
false;
408#if defined(MAP_ANONYMOUS)
410#define MYANONFLAG MAP_ANONYMOUS
411#elif defined(MAP_ANON)
413#define MYANONFLAG MAP_ANON
418 void* retVal = ::mmap(0,
len, PROT_READ | PROT_WRITE,
419 MYANONFLAG | MAP_SHARED, -1, 0);
420 if (MAP_FAILED == retVal) {
426 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
427 __FILE__ <<
", line " << __LINE__ <<
428 "): anonymous mmapping works, excellent!" <<
440 int fd = ::open(
"/dev/zero", O_RDWR);
442 throw Exception(
"open /dev/zero", errno);
443 void* retVal = ::mmap(0,
len,
444 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
445 if (MAP_FAILED == retVal) {
453 if (-1 == ::close(fd))
454 throw Exception(
"close /dev/zero", errno);
456 std::cerr <<
" INFO: In " << __func__ <<
" (" << __FILE__ <<
457 ", line " << __LINE__ <<
"): mmapping /dev/zero works, "
458 "very good!" << std::endl;
467 if (-1 == (fd = ::mkstemp(
const_cast<char*
>(
name.c_str()))))
throw Exception(
"mkstemp", errno);
469 if (-1 == ::unlink(
name.c_str())) {
475 if (-1 == ::lseek(fd,
len - 1, SEEK_SET)) {
481 if (1 != ::write(fd,
name.c_str(), 1)) {
487 void* retVal = ::mmap(0,
len,
488 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
489 if (MAP_FAILED == retVal) {
497 if (-1 == ::close(fd)) {
499 ::munmap(retVal,
len);
503 std::cerr <<
" INFO: In " << __func__ <<
" (" << __FILE__ <<
504 ", line " << __LINE__ <<
"): mmapping temporary files "
505 "works, good!" << std::endl;
516 std::cerr <<
"WARNING: In " << __func__ <<
" (" << __FILE__ <<
517 ", line " << __LINE__ <<
"): anonymous mmapping of "
518 "shared buffers failed, falling back to read/write on "
519 " pipes!" << std::endl;
523 void* retVal = std::malloc(
len);
524 if (!retVal)
throw Exception(
"malloc", errno);
538 if (-1 == ::munmap(addr,
len))
560 unsigned char* p0 =
reinterpret_cast<unsigned char*
>(
m_begin);
561 unsigned char* p1 =
reinterpret_cast<unsigned char*
>(
p[0u]);
563 unsigned char* p3 =
reinterpret_cast<unsigned char*
>(
m_end);
564 if (p1 != p0) ::mprotect(p0, p1 - p0, PROT_NONE);
565 if (p2 != p3) ::mprotect(p2, p3 - p2, PROT_NONE);
570 p.m_pimpl->m_parent = 0;
577 m_cursz(minsz), m_nPgPerGrp(nPgPerGroup)
582 const unsigned mult =
586 const unsigned actual = mult *
587 (desired / mult +
bool(desired % mult));
590 std::cerr <<
" INFO: In " << __func__ <<
" (" <<
591 __FILE__ <<
", line " << __LINE__ <<
593 ", subdividing into logical pages of size " <<
616 for (ChunkList::iterator it =
m_chunks.begin();
m_chunks.end() != it; ++it) {
617 if ((*it)->contains(
p)) {
649 assert(chunk->
empty());
651 ChunkList::iterator it = std::find(
654 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
659 throw Exception(
"PagePool::release(PageChunk*)", EINVAL);
668 assert(!chunk->
full());
732 if (
p->m_childPid) kill(
p->m_childPid, SIGTERM);
733 p->doClose(
true,
true);
740 m_pages(pagepool().pop())
751 m_pages(pagepool().pop()), m_busylist(0), m_freelist(0), m_dirtylist(0),
752 m_inpipe(-1), m_outpipe(-1), m_flags(failbit), m_childPid(0),
753 m_parentPid(::getpid())
758 int fds[4] = { -1, -1, -1, -1 };
760 static bool firstcall =
true;
773 for (
unsigned i = 1; i <
TotPages; ++i)
776 if (!useSocketpair) {
778 if (0 != ::pipe(&fds[0]))
throw Exception(
"pipe", errno);
779 if (0 != ::pipe(&fds[2]))
throw Exception(
"pipe", errno);
781 if (0 != ::socketpair(AF_UNIX, SOCK_STREAM, 0, &fds[0]))
802 fds[0] = fds[3] = -1;
817 for (std::list<BidirMMapPipe*>::iterator it =
s_openpipes.begin();
821 p->doClose(
true,
true);
834 throw Exception(
"handshake: xferraw write", EPIPE);
836 throw Exception(
"handshake: xferraw read", EPIPE);
837 if (
'P' !=
c)
throw Exception(
"handshake", EPIPE);
848 fds[1] = fds[2] = -1;
870 throw Exception(
"handshake: xferraw write", EPIPE);
872 throw Exception(
"handshake: xferraw read", EPIPE);
873 if (
'C' !=
c)
throw Exception(
"handshake", EPIPE);
879 if (-1 == ::fcntl(
m_outpipe, F_GETFD, &fdflags))
881 fdflags |= FD_CLOEXEC;
882 if (-1 == ::fcntl(
m_outpipe, F_SETFD, fdflags))
885 if (-1 == ::fcntl(
m_inpipe, F_GETFD, &fdflags))
887 fdflags |= FD_CLOEXEC;
888 if (-1 == ::fcntl(
m_inpipe, F_SETFD, fdflags))
896 for (
int i = 0; i < 4; ++i)
897 if (-1 != fds[i] && 0 != fds[i])
::close(fds[i]);
928 if (!force)
throw Exception(
"close", errno);
950 while ((err =
::poll(&fds, 1, 1 << 20)) >= 0) {
951 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
break;
952 if (fds.revents & POLLIN) {
957 }
while (0 > err && EINTR == errno);
962 if (!force)
throw Exception(
"close", errno);
971 }
catch (std::exception&) {
981 }
while (-1 == tmp && EINTR == errno);
983 if (!force)
throw Exception(
"waitpid", errno);
988 std::list<BidirMMapPipe*>::iterator it = std::find(
1001 ssize_t (*xferfn)(
int,
void*, std::size_t))
1004 unsigned char* buf =
reinterpret_cast<unsigned char*
>(addr);
1006 ssize_t tmp = xferfn(fd, buf,
len);
1012 }
else if (0 == tmp) {
1015 }
else if (-1 == tmp) {
1022 if (xferred)
return xferred;
1026#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
1029 std::cerr <<
" ERROR: In " << __func__ <<
" (" <<
1030 __FILE__ <<
", line " << __LINE__ <<
1031 "): expect transfer to block!" << std::endl;
1037 throw Exception(
"xferraw: unexpected return value from read/write",
1047 unsigned char pg =
m_pages[plist];
1052 for (
Page*
p = plist;
p;
p =
p->next()) {
1053 if (
sizeof(
Page) +
p->size() !=
1056 throw Exception(
"sendpages: short write", EPIPE);
1061 throw Exception(
"sendpages: short write", EPIPE);
1063 }
else { assert(plist); }
1069 unsigned retVal = 0;
1070 Page *plisthead = 0, *plisttail = 0;
1072 plisthead = plisttail =
m_pages[pg];
1077 for (; plisttail; ++retVal) {
1078 Page*
p = plisttail;
1081 plisttail =
p->next();
1082 if (!
p->size())
continue;
1103 fds.events = POLLIN;
1105 unsigned retVal = 0;
1107 int rc =
::poll(&fds, 1, 0);
1109 if (EINTR == errno)
continue;
1112 if (1 == retVal && fds.revents & POLLIN &&
1113 !(fds.revents & (POLLNVAL | POLLERR))) {
1127 for ( ;
p;
p =
p->next()) ++
n;
1136 while (blend && blend->
next()) blend = blend->
next();
1140 Page *sendlisthead = 0, *sendlisttail = 0;
1161 if (!sendlisthead) sendlisthead =
p;
1162 if (sendlisttail) sendlisttail->setNext(
p);
1182 sendlisttail->setNext(
p);
1190 struct pollfd fds[2];
1192 fds[0].events = fds[0].revents = 0;
1195 fds[1].events = fds[1].revents = 0;
1197 fds[0].events |= POLLIN;
1201 retVal =
::poll(fds, nfds, 0);
1202 if (0 > retVal && EINTR == errno)
1207 bool ok = !(fds[0].revents & (POLLERR | POLLNVAL | POLLHUP));
1209 ok = ok && !(fds[1].revents & (POLLERR | POLLNVAL | POLLHUP));
1211 if (ok && fds[0].revents & POLLIN) {
1213 if (!ret) ok =
false;
1222 throw Exception(
"feedPageLists: poll", errno);
1236 while (dl && dl->
next()) dl = dl->
next();
1258 if (
p)
while (
p->next())
p =
p->next();
1259 if (!
p ||
p->full()) {
1274 Page *flushlisthead = 0, *flushlisttail = 0;
1277 if (!forcePartialPages && !
p->full())
break;
1282 if (!flushlisthead) flushlisthead =
p;
1283 if (flushlisttail) flushlisttail->setNext(
p);
1286 if (flushlisthead)
sendpages(flushlisthead);
1295 while (
l &&
l->next())
l =
l->next();
1313 retVal +=
p->size() -
p->pos();
1324 bool couldwrite =
false;
1328 fds.events = POLLOUT;
1332 retVal =
::poll(&fds, 1, 0);
1334 if (EINTR == errno)
continue;
1335 throw Exception(
"bytesWritableNonBlocking: poll", errno);
1337 if (1 == retVal && fds.revents & POLLOUT &&
1338 !(fds.revents & (POLLNVAL | POLLERR | POLLHUP)))
1345 unsigned npages = 0;
1351 retVal +=
p->free();
1367 unsigned char *ap =
reinterpret_cast<unsigned char*
>(addr);
1376 unsigned char* pp =
p->begin() +
p->pos();
1378 std::copy(pp, pp + csz, ap);
1383 assert(
p->size() >=
p->pos());
1384 if (
p->size() ==
p->pos()) {
1403 const unsigned char *ap =
reinterpret_cast<const unsigned char*
>(addr);
1412 unsigned char* pp =
p->begin() +
p->size();
1414 std::copy(ap, ap + csz, pp);
1419 assert(
p->capacity() >=
p->size());
1439 bool canskiptimeout =
false;
1441 std::vector<unsigned>::iterator mit =
masks.begin();
1442 for (PollVector::iterator it = pipes.begin(); pipes.end() != it;
1449 canskiptimeout =
true;
1470 while (dl && dl->
next()) dl = dl->
next();
1475 if (pe.
revents) canskiptimeout =
true;
1478 std::vector<pollfd> fds;
1479 fds.reserve(2 * pipes.size());
1480 std::map<int, PollEntry*> fds2pipes;
1481 for (PollVector::const_iterator it = pipes.begin();
1482 pipes.end() != it; ++it) {
1485 fds2pipes.insert(std::make_pair((tmp.fd = pe.
pipe->
m_inpipe),
1487 tmp.
events = tmp.revents = 0;
1490 tmp.events |= POLLIN;
1494 fds2pipes.insert(std::make_pair(
1506 retVal =
::poll(&fds[0], fds.size(), canskiptimeout ? 0 : timeout);
1508 if (EINTR == errno)
continue;
1514 for (std::vector<pollfd>::iterator it = fds.begin();
1515 fds.end() != it; ++it) {
1521 if (fe.revents & POLLNVAL && fe.fd == pe.
pipe->
m_inpipe)
1525 if (fe.revents & POLLERR && fe.fd == pe.
pipe->
m_inpipe)
1529 if (fe.revents & POLLHUP && fe.fd == pe.
pipe->
m_inpipe)
1533 if ((fe.revents & POLLIN) && fe.fd == pe.
pipe->
m_inpipe &&
1534 !(fe.revents & (POLLNVAL | POLLERR))) {
1540 int tmp =
::poll(&fe, 1, 0);
1541 if (tmp > 0)
goto oncemore;
1543 if (EINTR == errno)
continue;
1555 while (dl && dl->
next()) dl = dl->
next();
1563 mit =
masks.begin();
1564 for (PollVector::iterator it = pipes.begin();
1565 pipes.end() != it; ++it, ++mit)
1566 if ((it->revents &= *mit)) ++npipes;
1572 size_t sz = std::strlen(str);
1574 if (sz)
write(str, sz);
1583 str =
reinterpret_cast<char*
>(std::realloc(str, sz + 1));
1584 if (!str)
throw Exception(
"realloc", errno);
1585 if (sz)
read(str, sz);
1593 size_t sz = str.size();
1595 write(str.data(), sz);
1606 for (
unsigned char c; sz--; str.push_back(
c)) *
this >>
c;
1613#ifdef TEST_BIDIRMMAPPIPE
1619 while (pipe.
good() && !pipe.
eof()) {
1623 if (!pipe)
return -1;
1624 if (pipe.
eof())
break;
1626 std::cout <<
"[CHILD] : read: " << str << std::endl;
1627 str =
"... early in the morning?";
1631 if (str.empty())
break;
1632 if (!pipe)
return -1;
1633 if (pipe.
eof())
break;
1634 std::cout <<
"[CHILD] : wrote: " << str << std::endl;
1644 ::srand48(::getpid());
1652 for (
int i = 0; i < 5; ++i) {
1654 ::usleep(
int(1e6 * ::drand48()));
1655 std::ostringstream buf;
1656 buf <<
"child pid " << ::getpid() <<
" sends message " << i;
1657 std::string str = buf.str();
1658 std::cout <<
"[CHILD] : " << str << std::endl;
1660 if (!pipe)
return -1;
1661 if (pipe.
eof())
break;
1677 while (pipe && !pipe.
eof()) {
1684 if (pipe.
eof())
break;
1687 if (!std::strlen(str))
break;
1698 while (pipe && !pipe.
eof()) {
1700 if (!std::strlen(str))
break;
1712 for (
unsigned i = 0; i <= 24; ++i) {
1713 str =
reinterpret_cast<char*
>(std::realloc(str, (1 << i) + 1));
1714 std::memset(str,
'4', 1 << i);
1716 for (
unsigned j = 0; j < 1 << 7; ++j) {
1718 if (!pipe || pipe.
eof()) {
1739 int retVal = childexec(*
p);
1746#include <sys/time.h>
1752 std::cout <<
"[PARENT]: simple challenge-response test, "
1753 "one child:" << std::endl;
1755 for (
int i = 0; i < 5; ++i) {
1756 std::string str(
"What shall we do with a drunken sailor...");
1758 if (!*pipe)
return -1;
1759 std::cout <<
"[PARENT]: wrote: " << str << std::endl;
1761 if (!*pipe)
return -1;
1762 std::cout <<
"[PARENT]: read: " << str << std::endl;
1769 int retVal = pipe->
close();
1770 std::cout <<
"[PARENT]: exit status of child: " << retVal <<
1772 if (retVal)
return retVal;
1778 std::cout << std::endl <<
"[PARENT]: polling test, " << nch <<
1779 " children:" << std::endl;
1785 for (
unsigned i = 0; i < nch; ++i) {
1786 std::cout <<
"[PARENT]: spawning child " << i << std::endl;
1787 pipes.push_back(PollEntry(spawnChild(randomchild),
1791 std::cout <<
"[PARENT]: waking up children" << std::endl;
1792 for (
unsigned i = 0; i < nch; ++i)
1794 std::cout <<
"[PARENT]: waiting for events on children's pipes" << std::endl;
1796 while (!pipes.empty()) {
1800 for (std::vector<PollEntry>::iterator it = pipes.begin();
1801 npipes && pipes.end() != it; ) {
1813 std::cout <<
"[PARENT]: Read from pipe " << it->pipe <<
1814 ": " << s << std::endl;
1827 std::cerr <<
"[DEBUG]: Event on pipe " << it->pipe <<
1830 ((it->revents &
BidirMMapPipe::Writable) ?
" Writable" :
"") <<
1831 ((it->revents &
BidirMMapPipe::ReadError) ?
" ReadError" :
"") <<
1832 ((it->revents &
BidirMMapPipe::WriteError) ?
" WriteError" :
"") <<
1833 ((it->revents &
BidirMMapPipe::ReadEndOfFile) ?
" ReadEndOfFile" :
"") <<
1834 ((it->revents &
BidirMMapPipe::WriteEndOfFile) ?
" WriteEndOfFile" :
"") <<
1835 ((it->revents &
BidirMMapPipe::ReadInvalid) ?
" ReadInvalid" :
"") <<
1836 ((it->revents &
BidirMMapPipe::WriteInvalid) ?
" WriteInvalid" :
"") <<
1839 int retVal = it->pipe->close();
1840 std::cout <<
"[PARENT]: child exit status: " <<
1841 retVal <<
", number of children still alive: " <<
1842 (pipes.size() - 1) << std::endl;
1843 if (retVal)
return retVal;
1845 it = pipes.erase(it);
1853 std::cout << std::endl <<
"[PARENT]: benchmark: round-trip times vs block size" << std::endl;
1854 for (
unsigned i = 0; i <= 24; ++i) {
1855 std::vector<char> s(1 + (1 << i));
1856 std::memset(s,
'A', 1 << i);
1858 const unsigned n = 1 << 7;
1859 double avg = 0., min = 1e42, max = -1e42;
1861 for (
unsigned j =
n; j--; ) {
1863 ::gettimeofday(&
t1, 0);
1865 if (!*pipe || pipe->
eof())
break;
1867 if (!*pipe || pipe->
eof())
break;
1869 ::gettimeofday(&t2, 0);
1870 t2.tv_sec -=
t1.tv_sec;
1871 t2.tv_usec -=
t1.tv_usec;
1873 if (dt < min) min = dt;
1874 if (dt > max) max = dt;
1882 avg *= 1e6; min *= 1e6; max *= 1e6;
1883 int retVal = pipe->
close();
1885 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1892 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1893 " avg " << std::setw(7) << avg <<
" us min " <<
1894 std::setw(7) << min <<
" us max " << std::setw(7) << max <<
1895 "us speed " << std::setw(9) <<
1897 " MB/s" << std::endl;
1899 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1903 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as sink" << std::endl;
1904 for (
unsigned i = 0; i <= 24; ++i) {
1905 std::vector<char> s(1 + (1 << i));
1906 std::memset(s,
'A', 1 << i);
1908 const unsigned n = 1 << 7;
1909 double avg = 0., min = 1e42, max = -1e42;
1911 for (
unsigned j =
n; j--; ) {
1913 ::gettimeofday(&
t1, 0);
1916 if (!*pipe || pipe->
eof())
break;
1918 ::gettimeofday(&t2, 0);
1919 t2.tv_sec -=
t1.tv_sec;
1920 t2.tv_usec -=
t1.tv_usec;
1922 if (dt < min) min = dt;
1923 if (dt > max) max = dt;
1931 avg *= 1e6; min *= 1e6; max *= 1e6;
1932 int retVal = pipe->
close();
1934 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1938 std::cout <<
"block size " << std::setw(9) << (1 << i) <<
1939 " avg " << std::setw(7) << avg <<
" us min " <<
1940 std::setw(7) << min <<
" us max " << std::setw(7) << max <<
1941 "us speed " << std::setw(9) <<
1943 " MB/s" << std::endl;
1945 std::cout <<
"[PARENT]: all children had exit code 0" << std::endl;
1949 std::cout << std::endl <<
"[PARENT]: benchmark: raw transfer rate with child as source" << std::endl;
1951 double avg = 0., min = 1e42, max = -1e42;
1952 unsigned n = 0, bsz = 0;
1954 while (*pipe && !pipe->
eof()) {
1956 ::gettimeofday(&
t1, 0);
1959 if (!*pipe || pipe->
eof())
break;
1961 ::gettimeofday(&t2, 0);
1962 t2.tv_sec -=
t1.tv_sec;
1963 t2.tv_usec -=
t1.tv_usec;
1965 if (std::strlen(s)) {
1967 if (dt < min) min = dt;
1968 if (dt > max) max = dt;
1970 bsz = std::strlen(s);
1975 avg *= 1e6; min *= 1e6; max *= 1e6;
1977 std::cout <<
"block size " << std::setw(9) << bsz <<
1978 " avg " << std::setw(7) << avg <<
" us min " <<
1979 std::setw(7) << min <<
" us max " << std::setw(7) <<
1980 max <<
"us speed " << std::setw(9) <<
1982 " MB/s" << std::endl;
1989 int retVal = pipe->
close();
1990 std::cout <<
"[PARENT]: child exited with code " << retVal << std::endl;
1991 if (retVal)
return retVal;
#define END_NAMESPACE_ROOFIT
#define BEGIN_NAMESPACE_ROOFIT
header file for BidirMMapPipe, a class which forks off a child process and serves as communications c...
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
unsigned events
events of interest (or'ed bitmask)
unsigned revents
events that happened (or'ed bitmask)
BidirMMapPipe * pipe
pipe of interest
exception to throw if low-level OS calls go wrong
static int dostrerror_r(int err, char *buf, std::size_t sz, int(*f)(int, char *, std::size_t))
for the POSIX version of strerror_r
virtual const char * what() const noexcept
return a destcription of what went wrong
class representing a chunk of pages
BidirMMapPipeException Exception
convenience typedef
std::list< void * > m_freelist
free pages list
void * m_end
pointer one behind end of mmapped area
static void domunmap(void *p, unsigned len)
munmap pages p, len is length of mmapped area in bytes
void * m_begin
pointer to start of mmapped area
void zap(Pages &p)
free all pages except for those pointed to by p
MMapVariety
type of mmap support found
@ FileBacked
mmapping a temp file works
@ Unknown
don't know yet what'll work
@ DevZero
mmapping /dev/zero works
@ Copy
mmap doesn't work, have to copy back and forth
@ Anonymous
anonymous mmap works
static unsigned pagesize()
return the logical page size
PagePool * m_parent
parent page pool
unsigned m_nUsedGrp
number of used page groups
static MMapVariety s_mmapworks
mmap variety that works on this system
static unsigned s_physpgsz
system physical page size
static void * dommap(unsigned len)
mmap pages, len is length of mmapped area in bytes
static MMapVariety mmapVariety()
return mmap variety support found
unsigned m_nPgPerGrp
number of pages per group
static unsigned physPgSz()
return the physical page size of the system
static unsigned s_pagesize
logical page size (run-time determined)
void push(const Pages &p)
push a group of pages onto the free list
Pages pop()
pop a group of pages off the free list
unsigned len() const
return length of chunk
PageChunk(const PageChunk &)
forbid copying
static unsigned getPageSize()
determine page size at run time
bool contains(const Pages &p) const
return if p is contained in this PageChunk
bool full() const
return true if no free page groups in this chunk
bool empty() const
return true if no used page groups in this chunk
class representing a page pool
void zap(Pages &p)
zap the pool (unmap all but Pages p)
void updateCurSz(int sz, int incr)
adjust _cursz to current largest block
unsigned m_nPgPerGrp
page group size
static unsigned pagesize()
return (logical) page size of the system
ChunkList m_chunks
list of chunks used by the pool
ChunkList m_freelist
list of chunks used by the pool which are not full
static MMapVariety mmapVariety()
return variety of mmap supported on the system
void putOnFreeList(Chunk *chunk)
release a chunk
Pages pop()
pop a free element out of the pool
int nextChunkSz() const
find size of next chunk to allocate (in a hopefully smart way)
BidirMMapPipeException Exception
convenience typedef
std::list< Chunk * > ChunkList
list of chunks
int m_cursz
current chunk size
PageChunk::MMapVariety MMapVariety
convenience typedef
@ szincr
size class increment (sz = 1 << (minsz + k * szincr))
@ minsz
minimum chunk size (just below 1 << minsz bytes)
@ maxsz
maximum chunk size (just below 1 << maxsz bytes)
unsigned nPagesPerGroup() const
return number of pages per group (ie. as returned by pop())
PagePool(unsigned nPagesPerGroup)
constructor
unsigned m_szmap[(maxsz - minsz)/szincr]
chunk size map (histogram of chunk sizes)
void release(Chunk *chunk)
release a chunk
BidirMMapPipe_impl::PageChunk Chunk
a chunk of memory in the pool
class representing the header structure in an mmapped page
unsigned char * begin() const
return pointer to first byte in payload data area of page
short m_next
next page in list (in pagesizes)
unsigned short & size()
return reference to size field
static unsigned capacity()
return the capacity of the page
unsigned short & pos()
return reference to position field
unsigned free() const
free space left (to be written to)
Page(const Page &)
copy construction forbidden
void setNext(const Page *p)
set pointer to next page
unsigned short m_pos
index of next byte in payload area
bool full() const
true if page completely full
unsigned short m_size
size of payload (in bytes)
unsigned size() const
return size (of payload data)
unsigned char * end() const
return pointer to first byte in payload data area of page
Page & operator=(const Page &)=delete
assigment forbidden
unsigned pos() const
return position
bool empty() const
true if page empty
Page * next() const
return pointer to next page
bool filled() const
true if page partially filled
unsigned remaining() const
bytes remaining to be read
handle class for a number of Pages
Pages & operator=(const Pages &other)
assignment operator
static unsigned pagesize()
return page size
unsigned pageno(Page *p) const
perform page to page number mapping
impl * m_pimpl
pointer to implementation
Page * page(unsigned pgno) const
return page number pageno
Pages()
default constructor
BidirMMapPipe creates a bidirectional channel between the current process and a child it forks.
void doFlush(bool forcePartialPages=true)
perform the flush
unsigned recvpages()
receive a pages from the other end (may block), queue them
std::vector< PollEntry > PollVector
convenience typedef for poll() interface
Page * m_busylist
linked list: busy pages (data to be read)
BidirMMapPipe_impl::BidirMMapPipeException Exception
convenience typedef for BidirMMapPipeException
@ PagesPerEnd
pages per pipe end
@ FlushThresh
flush threshold
@ TotPages
pages shared (child + parent)
BidirMMapPipe_impl::Pages m_pages
mmapped pages
void flush()
flush buffers with unwritten data
static BidirMMapPipe_impl::PagePool & pagepool()
return page pool
static BidirMMapPipe_impl::PagePool * s_pagepool
pool of mmapped pages
size_type write(const void *addr, size_type sz)
wirte to pipe
bool good() const
status of stream is good
static int poll(PollVector &pipes, int timeout)
poll a set of pipes for events (ready to read from, ready to write to, error)
bool isChild() const
return if this end of the pipe is the child end
static void teardownall(void)
cleanup routine - at exit, we want our children to get a SIGTERM...
bool eof() const
true if end-of-file
static std::list< BidirMMapPipe * > s_openpipes
list of open BidirMMapPipes
static unsigned lenPageList(const Page *list)
return length of a page list
Page * dirtypage()
get a dirty page to write data to (may block)
int close()
flush buffers, close pipe
int m_flags
flags (e.g. end of file)
BidirMMapPipe(bool useExceptions=true, bool useSocketpair=false)
constructor (forks!)
void sendpages(Page *plist)
send page(s) to the other end (may block)
bool bad() const
true on I/O error
~BidirMMapPipe()
destructor
int doClose(bool force, bool holdlock=false)
close the pipe (no flush if forced)
BidirMMapPipe & operator<<(const bool &val)
bool closed() const
true if closed
size_type bytesReadableNonBlocking()
number of bytes that can be read without blocking
int m_inpipe
pipe end from which data may be read
static unsigned s_pagepoolrefcnt
page pool reference counter
@ failbit
logical failure (e.g. pipe closed)
@ eofbit
end of file reached
@ exceptionsbit
error reporting with exceptions
Page * m_dirtylist
linked list: dirty pages (data to be sent)
bool isParent() const
return if this end of the pipe is the parent end
static pthread_mutex_t s_openpipesmutex
protects s_openpipes
@ ReadError
pipe error read end
@ Writable
pipe can be written to
@ ReadInvalid
read end of pipe invalid
@ WriteEndOfFile
write pipe in end-of-file state
@ WriteInvalid
write end of pipe invalid
@ None
nothing special on this pipe
@ ReadEndOfFile
read pipe in end-of-file state
@ WriteError
pipe error Write end
@ Readable
pipe has data for reading
unsigned recvpages_nonblock()
receive pages from other end (non-blocking)
static int debugflag()
return the current setting of the debug flag
BidirMMapPipe & operator>>(bool &val)
void purge()
purge buffered data waiting to be read and/or written
size_type bytesWritableNonBlocking()
number of bytes that can be written without blocking
void feedPageLists(Page *plist)
"feed" the busy and free lists with a list of pages
Page * busypage()
get a busy page to read data from (may block)
size_type read(void *addr, size_type sz)
read from pipe
std::size_t size_type
type used to represent sizes
static size_type xferraw(int fd, void *addr, size_type len, ssize_t(*xferfn)(int, void *, std::size_t))
transfer bytes through the pipe (reading, writing, may block)
static int s_debugflag
debug flag
int m_outpipe
pipe end to which data may be written
Page * m_freelist
linked list: free pages
pid_t m_childPid
pid of the child (zero if we're child)
void markPageDirty(Page *p)
put on dirty pages list
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
std::string const & tmpPath()
Returns the path to the directory that should be used for temporary RooFit files (e....
Page * m_pages
pointer to first page
unsigned m_refcnt
reference counter
unsigned char m_npages
length in pages
PageChunk * m_parent
pointer to parent pool
static unsigned long masks[]