void ChatGreeter::welcome(Publisher atPub, const std::string& nodeId, const std::string& subId) { Message* greeting = Message::toSubscriber(subId); greeting->putMeta("participant", _username); greeting->putMeta("subscriber", _subId); atPub.send(greeting); delete greeting; }
void receive(Message* msg) { RScopeLock lock(mutex); uint64_t currServerTimeStamp; Message::read(msg->data(), &currSeqNr); Message::read(msg->data() + 8, &currServerTimeStamp); Message::read(msg->data() + 16, &reportInterval); if (currSeqNr < lastSeqNr) { // new throughput run! lastSeqNr = 0; timeStampServerFirst = 0; currReportNr = 0; bytesRcvd = 0; pktsRecvd = 0; pktsDropped = 0; } bytesRcvd += msg->size(); pktsRecvd++; if (timeStampServerFirst == 0) timeStampServerFirst = currServerTimeStamp; if (lastSeqNr > 0 && lastSeqNr != currSeqNr - 1) { pktsDropped += currSeqNr - lastSeqNr; } lastSeqNr = currSeqNr; // reply? if (currServerTimeStamp - reportInterval >= timeStampServerLast) { RScopeLock lock(mutex); timeStampServerLast = currServerTimeStamp; Message* msg = new Message(); msg->putMeta("bytes.rcvd", toStr(bytesRcvd)); msg->putMeta("pkts.dropped", toStr(pktsDropped)); msg->putMeta("pkts.rcvd", toStr(pktsRecvd)); msg->putMeta("last.seq", toStr(lastSeqNr)); msg->putMeta("report.seq", toStr(currReportNr++)); msg->putMeta("timestamp.server.last", toStr(timeStampServerLast)); msg->putMeta("timestamp.server.first", toStr(timeStampServerFirst)); msg->putMeta("hostname", umundo::Host::getHostname()); reporter.send(msg); delete msg; pktsDropped = 0; pktsRecvd = 0; bytesRcvd = 0; } }
void testDomainReception() { Node* fooNode1 = new Node("foo"); Node* fooNode2 = new Node("foo"); Node* barNode = new Node("bar"); assert(Node::instances == 3); Subscriber* sub = new Subscriber("test1", new TestReceiver("test1")); Publisher* pub = new Publisher("test1"); fooNode1->addPublisher(pub); fooNode2->addPublisher(pub); barNode->addPublisher(pub); fooNode1->addSubscriber(sub); fooNode2->addSubscriber(sub); barNode->addSubscriber(sub); char buffer[BUFFER_SIZE]; for (int i = 0; i < BUFFER_SIZE; i++) { buffer[i] = (char)i%255; } pub->waitForSubscribers(1); assert(pub->waitForSubscribers(1) >= 1); Thread::sleepMs(100); int iterations = 10; // this has to be less or equal to the high water mark / 3 receives = 0; for (int i = 0; i < iterations; i++) { Message* msg = new Message(); msg->setData(buffer, BUFFER_SIZE); msg->setMeta("type", "foo!"); pub->send(msg); delete(msg); } Thread::sleepMs(200); std::cout << "Received " << receives << " messages, expected " << iterations << " messages" << std::endl; // assert(receives == iterations); delete(fooNode1); delete(fooNode2); delete(barNode); delete(sub); delete(pub); }
void runAsServer() { ThroughputGreeter tpGreeter; Publisher pub; switch (type) { case PUB_RTP: { PublisherConfigRTP config("throughput.rtp"); config.setTimestampIncrement(166); pub = Publisher(&config); pub.setGreeter(&tpGreeter); break; } case PUB_MCAST: { PublisherConfigMCast config("throughput.mcast"); config.setTimestampIncrement(166); // config.setPortbase(42142); pub = Publisher(&config); pub.setGreeter(&tpGreeter); break; } case PUB_TCP: { pub = Publisher("throughput.tcp"); pub.setGreeter(&tpGreeter); break; } } node.addPublisher(pub); disc.add(node); timeStampStartedAt = Thread::getTimeStampMs(); if (duration > 0) duration *= 1000; // convert to ms pub.waitForSubscribers(waitForSubs); // reserve 20 bytes for timestamp, sequence number and report interval size_t dataSize = (std::max)(mtu, (size_t)20); char* data = (char*)malloc(dataSize); Message* msg = NULL; if (useZeroCopy) { msg = new Message(data, dataSize, doneCallback, (void*)NULL); } else { msg = new Message(); } uint64_t lastReportAt = Thread::getTimeStampMs(); while(1) { uint64_t now = Thread::getTimeStampMs(); if (duration > 0 && now - timeStampStartedAt > duration) break; // first 16 bytes are seqNr and timestamp Message::write(&data[0], ++currSeqNr); Message::write(&data[8], now); Message::write(&data[16], reportInterval); if (!useZeroCopy) { msg->setData(data, dataSize); } pub.send(msg); intervalFactor = 1000.0 / (double)reportInterval; bytesWritten += dataSize; bytesTotal += dataSize; packetsWritten++; // sleep just enough to reach the desired bps { RScopeLock lock(mutex); size_t packetsPerSecond = (std::max)(bytesPerSecond / dataSize, (size_t)1); delay = (std::max)((1000000) / (packetsPerSecond), (size_t)1); } // every report interval we are recalculating bandwith if (now - lastReportAt > reportInterval) { RScopeLock lock(mutex); std::string scaleInfo("--"); // and recalculate bytes to send if (reports.size() > 0) { double decreasePressure = 0; // print report messages std::map<std::string, Report>::iterator repIter = reports.begin(); // bandwidth is not fixed if (fixedBytesPerSecond == 0) { while(repIter != reports.end()) { const Report& report = repIter->second; double reportPressure = 0; // see if we need to decrease bandwidth if (report.pktsLate > packetsWritten / 2) { // client is lagging more than half a second, scale back somewhat reportPressure = (std::max)(1.1, reportPressure); } if (report.pcntLoss > pcntLossOk) { // we lost packages, scale back somewhat reportPressure = (std::max)((double)report.pktsDropped / report.pktsRcvd, reportPressure); reportPressure = (std::min)(reportPressure, 1.4); } if (report.pktsLate > 3 * packetsWritten) { // queues explode! scale back alot! reportPressure = (std::max)((double)report.pktsLate / packetsWritten, reportPressure); reportPressure = (std::min)(reportPressure, 2.0); } if (reportPressure > decreasePressure) decreasePressure = reportPressure; repIter++; } if (decreasePressure > 1) { bytesPerSecond *= (1.0 / decreasePressure); bytesPerSecond = (std::max)(bytesPerSecond, (size_t)(1024)); scaleInfo = "down " + toStr(1.0 / decreasePressure); } else { bytesPerSecond *= 1.2; scaleInfo = "up 1.2"; } std::cout << std::endl; } else { if (bytesWritten * intervalFactor < fixedBytesPerSecond) { bytesPerSecond *= 1.05; } else if (bytesWritten * intervalFactor > fixedBytesPerSecond) { bytesPerSecond *= 0.95; } } } currReportNr++; writeReports(scaleInfo); bytesWritten = 0; packetsWritten = 0; lastReportAt = Thread::getTimeStampMs(); } // now we sleep until we have to send another packet Thread::sleepUs(delay); } pub.setGreeter(NULL); delete(msg); }
void runAsServer() { ThroughputGreeter tpGreeter; Publisher pub; PublisherConfig* config = NULL; switch (type) { case PUB_RTP: { config = new PublisherConfigRTP("throughput.rtp"); ((PublisherConfigRTP*)config)->setTimestampIncrement(166); break; } case PUB_MCAST: { config = new PublisherConfigMCast("throughput.mcast"); ((PublisherConfigMCast*)config)->setTimestampIncrement(166); // config.setPortbase(42142); break; } case PUB_TCP: { config = new PublisherConfigTCP ("throughput.tcp"); break; } } if (compressionType.size() != 0) config->enableCompression(compressionType, compressionWithState, compressionLevel, compressionRefreshInterval); pub = Publisher(config); pub.setGreeter(&tpGreeter); delete config; node.addPublisher(pub); disc.add(node); timeStampStartedDiscovery = Thread::getTimeStampMs(); if (duration > 0) duration *= 1000; // convert to ms // open file with data std::ifstream fin(streamFile, std::ios::in | std::ios::binary); if (fin) { // streamFile exists on filesyste,, slurp content into streamData streamData = std::string((std::istreambuf_iterator<char>(fin) ), (std::istreambuf_iterator<char>() )); } else { // stream file is no actual file, interpret as "size:compressability" char* compArg = streamFile; // http://stackoverflow.com/a/53878/990120 std::list<std::string> compArgs; do { const char *begin = compArg; while(*compArg != ':' && *compArg) compArg++; compArgs.push_back(std::string(begin, compArg - begin)); } while(0 != *compArg++); size_t streamDataSize = 0; double compressibility = 50; if (compArgs.size() < 1) printUsageAndExit(); streamDataSize = displayToBytes(compArgs.front()); compArgs.pop_front(); if (!compArgs.empty()) { compressibility = strTo<double>(compArgs.front()); if (toStr(compressibility) != compArgs.front()) printUsageAndExit(); compArgs.pop_front(); } if (!compArgs.empty()) { printUsageAndExit(); } streamData.resize(streamDataSize); RDG_genBuffer(&streamData[0], streamDataSize, 1 - (compressibility/(double)100), 0.0, 0); } { // determine compressionActualRatio Message msg(streamData.data(), streamData.size()); size_t compressMaxPayload = msg.getCompressBounds("lz4", NULL, Message::Compression::PAYLOAD); char* compressPayloadData = (char*)malloc(compressMaxPayload); size_t compressActualPayload = msg.compress("lz4", NULL, compressPayloadData, compressMaxPayload, Message::Compression::PAYLOAD); compressionActualRatio = 100 * ((double)compressActualPayload / streamData.size()); } pub.waitForSubscribers(waitForSubs); timeStampStartedPublishing = Thread::getTimeStampMs(); uint64_t lastReportAt = Thread::getTimeStampMs(); size_t streamDataOffset = 0; while(1) { // fill data from stream data Message* msg = new Message((char*)malloc(mtu), mtu); size_t msgDataOffset = 0; while(true) { size_t toRead = (mtu - msgDataOffset <= streamData.size() - streamDataOffset ? mtu - msgDataOffset : streamData.size() - streamDataOffset); memcpy(&msg->data()[msgDataOffset], &streamData[streamDataOffset], toRead); msgDataOffset += toRead; streamDataOffset += toRead; // UM_LOG_WARN("%d: %d / %d", streamData.size(), msgDataOffset, streamDataOffset); if (msgDataOffset == mtu) break; if (streamData.size() == streamDataOffset) streamDataOffset = 0; } // UM_LOG_WARN("%d: %s", msg->size(), md5(msg->data(), msg->size()).c_str()); uint64_t now = Thread::getTimeStampMs(); if (duration > 0 && now - timeStampStartedPublishing > duration) break; // first 16 bytes are seqNr and timestamp Message::write(&msg->data()[0], ++currSeqNr); Message::write(&msg->data()[8], now); Message::write(&msg->data()[16], reportInterval); // msg->putMeta("md5", md5(msg->data(), msg->size())); intervalFactor = 1000.0 / (double)reportInterval; bytesWritten += msg->size(); bytesTotal += msg->size(); packetsWritten++; // sleep just enough to reach the desired bps { RScopeLock lock(mutex); size_t packetsPerSecond = (std::max)(bytesPerSecond / msg->size(), (size_t)1); delay = (std::max)((1000000) / (packetsPerSecond), (size_t)1); } // sending with compression will alter msg->size(); not anymore ... pub.send(msg); // every report interval we are recalculating bandwith if (now - lastReportAt > reportInterval) { RScopeLock lock(mutex); std::string scaleInfo("--"); // and recalculate bytes to send if (reports.size() > 0) { double decreasePressure = 0; // print report messages std::map<std::string, Report>::iterator repIter = reports.begin(); // bandwidth is fixed if (fixedBytesPerSecond == 0) { while(repIter != reports.end()) { const Report& report = repIter->second; double reportPressure = 0; // see if we need to decrease bandwidth if (report.pktsLate > packetsWritten / 2) { // client is lagging more than half a second, scale back somewhat reportPressure = (std::max)(1.1, reportPressure); } if (report.pcntLoss > pcntLossOk) { // we lost packages, scale back somewhat reportPressure = (std::max)((double)report.pktsDropped / report.pktsRcvd, reportPressure); reportPressure = (std::min)(reportPressure, 1.4); } if (report.pktsLate > 3 * packetsWritten) { // queues explode! scale back alot! reportPressure = (std::max)((double)report.pktsLate / packetsWritten, reportPressure); reportPressure = (std::min)(reportPressure, 2.0); } if (reportPressure > decreasePressure) decreasePressure = reportPressure; repIter++; } if (decreasePressure > 1) { bytesPerSecond *= (1.0 / decreasePressure); bytesPerSecond = (std::max)(bytesPerSecond, (size_t)(1024)); scaleInfo = "down " + toStr(1.0 / decreasePressure); } else { bytesPerSecond *= 1.3; scaleInfo = "up 1.3"; } std::cout << std::endl; } else if (fixedBytesPerSecond == (size_t)-1) { // do nothing } else { if (bytesWritten * intervalFactor < fixedBytesPerSecond) { bytesPerSecond *= 1.05; } else if (bytesWritten * intervalFactor > fixedBytesPerSecond) { bytesPerSecond *= 0.95; } } } currReportNr++; writeReports(scaleInfo); bytesWritten = 0; packetsWritten = 0; lastReportAt = Thread::getTimeStampMs(); } delete(msg); // now we sleep until we have to send another packet if (delay > 50 && fixedBytesPerSecond != (size_t) - 1) Thread::sleepUs(delay); } pub.setGreeter(NULL); }
void receive(Message* msg) { RScopeLock lock(mutex); if (msg->getMeta("md5").size() > 0 && msg->getMeta("md5") != md5(msg->data(), msg->size())) { UM_LOG_WARN("Corrupted message received"); } uint64_t currServerTimeStamp; Message::read(msg->data(), &currSeqNr); Message::read(msg->data() + 8, &currServerTimeStamp); Message::read(msg->data() + 16, &reportInterval); if (currSeqNr < lastSeqNr) { // new throughput run! lastSeqNr = 0; timeStampServerFirst = 0; timeStampServerLast = 0; currReportNr = 0; bytesRcvd = 0; pktsRecvd = 0; pktsDropped = 0; } bytesRcvd += msg->size(); pktsRecvd++; if (timeStampServerFirst == 0) timeStampServerFirst = currServerTimeStamp; if (lastSeqNr > 0 && lastSeqNr != currSeqNr - 1) { pktsDropped += currSeqNr - lastSeqNr; } lastSeqNr = currSeqNr; compressRatioHead += (msg->getMeta().find("um.compressRatio.head") != msg->getMeta().end() ? strTo<double>(msg->getMeta("um.compressRatio.head")) : 100); compressRatioPayload += (msg->getMeta().find("um.compressRatio.payload") != msg->getMeta().end() ? strTo<double>(msg->getMeta("um.compressRatio.payload")) : 100); // if (timeStampServerLast == 0) // timeStampServerLast = currServerTimeStamp; // may happen when initializing timeStampServerLast in client if (timeStampServerLast > currServerTimeStamp) timeStampServerLast = currServerTimeStamp; // reply? if (currServerTimeStamp - reportInterval >= timeStampServerLast) { RScopeLock lock(mutex); timeStampServerLast = currServerTimeStamp; Message* msg = new Message(); msg->putMeta("bytes.rcvd", toStr(bytesRcvd)); msg->putMeta("pkts.dropped", toStr(pktsDropped)); msg->putMeta("compress.ratio.head", toStr(compressRatioHead / (double)pktsRecvd)); msg->putMeta("compress.ratio.payload", toStr(compressRatioPayload / (double)pktsRecvd)); msg->putMeta("pkts.rcvd", toStr(pktsRecvd)); msg->putMeta("last.seq", toStr(lastSeqNr)); msg->putMeta("report.seq", toStr(currReportNr++)); msg->putMeta("timestamp.server.last", toStr(timeStampServerLast)); msg->putMeta("timestamp.server.first", toStr(timeStampServerFirst)); msg->putMeta("hostname", umundo::Host::getHostname()); reporter.send(msg); delete msg; pktsDropped = 0; pktsRecvd = 0; bytesRcvd = 0; compressRatioHead = 0; compressRatioPayload = 0; } }