Merged changes from default branch

This commit is contained in:
Andrew Johnson
2014-04-18 16:58:06 -05:00
21 changed files with 2373 additions and 2086 deletions
+1
View File
@@ -122,3 +122,4 @@ pvAccessApp/ca/caChannel.h
pvAccessApp/ca/caChannel.cpp
testApp/utils/Makefile
testApp/remote/channelAccessIFTest.cpp
testApp/remote/channelAccessIFTest.h
+1 -1
View File
@@ -155,7 +155,7 @@ namespace epics {
return false;
}
virtual void startMessage(epics::pvData::int8 command, std::size_t ensureCapacity);
virtual void startMessage(epics::pvData::int8 command, std::size_t ensureCapacity, epics::pvData::int32 payloadSize = 0);
virtual void endMessage();
virtual void flush(bool /*lastMessageCompleted*/) {
+2 -2
View File
@@ -173,13 +173,13 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so
// noop (note different sent addresses are possible)
}
void BlockingUDPTransport::startMessage(int8 command, size_t /*ensureCapacity*/) {
void BlockingUDPTransport::startMessage(int8 command, size_t /*ensureCapacity*/, int32 payloadSize) {
_lastMessageStartPosition = _sendBuffer->getPosition();
_sendBuffer->putByte(PVA_MAGIC);
_sendBuffer->putByte(PVA_VERSION);
_sendBuffer->putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess
_sendBuffer->putByte(command); // command
_sendBuffer->putInt(0); // temporary zero payload
_sendBuffer->putInt(payloadSize);
}
void BlockingUDPTransport::endMessage() {
+185 -15
View File
@@ -95,6 +95,7 @@ namespace epics {
}
// thows io_exception, connection_closed_exception, invalid_stream_exception
void AbstractCodec::processRead() {
switch (_readMode)
{
@@ -565,7 +566,8 @@ namespace epics {
void AbstractCodec::startMessage(
epics::pvData::int8 command,
std::size_t ensureCapacity) {
std::size_t ensureCapacity,
epics::pvData::int32 payloadSize) {
_lastMessageStartPosition =
std::numeric_limits<size_t>::max(); // TODO revise this
@@ -577,7 +579,7 @@ namespace epics {
_sendBuffer->putByte(
(_lastSegmentedMessageType | _byteOrderFlag)); // data + endian
_sendBuffer->putByte(command); // command
_sendBuffer->putInt(0); // temporary zero payload
_sendBuffer->putInt(payloadSize);
// apply offset
if (_nextMessagePayloadOffset > 0)
@@ -699,11 +701,7 @@ namespace epics {
flush(false);
}
void AbstractCodec::flush(bool lastMessageCompleted) {
// automatic end
endMessage(!lastMessageCompleted);
void AbstractCodec::flushSendBuffer() {
_sendBuffer->flip();
@@ -722,6 +720,15 @@ namespace epics {
_sendBuffer->clear();
_lastMessageStartPosition = std::numeric_limits<size_t>::max();
}
void AbstractCodec::flush(bool lastMessageCompleted) {
// automatic end
endMessage(!lastMessageCompleted);
// flush send buffer
flushSendBuffer();
// start with last header
if (!lastMessageCompleted && _lastSegmentedMessageType != 0)
@@ -729,9 +736,9 @@ namespace epics {
}
// thows io_exception, connection_closed_exception
void AbstractCodec::processWrite() {
// TODO catch ConnectionClosedException, InvalidStreamException?
switch (_writeMode)
{
case PROCESS_SEND_QUEUE:
@@ -885,7 +892,7 @@ namespace epics {
std::ostringstream msg;
msg << "an exception caught while processing a send message: "
<< e.what();
LOG(logLevelWarn, "%s at %s:%d",
LOG(logLevelDebug, "%s at %s:%d",
msg.str().c_str(), __FILE__, __LINE__);
try {
@@ -935,6 +942,146 @@ namespace epics {
}
bool AbstractCodec::directSerialize(ByteBuffer* /*existingBuffer*/, const char* toSerialize,
std::size_t elementCount, std::size_t elementSize)
{
// TODO overflow check of "size_t count", overflow int32 field of payloadSize header field
// TODO max message size in connection validation
std::size_t count = elementCount * elementSize;
// TODO find smart limit
// check if direct mode actually pays off
if (count < 64*1024)
return false;
//
// first end current message, and write a header of next "directly serialized" message
//
// first end current message indicating the we will segment
endMessage(true);
// append segmented message header with payloadSize == count
// TODO size_t to int32
startMessage(_lastSegmentedMessageCommand, 0, static_cast<int32>(count));
// flush
flushSendBuffer();
// TODO think if alignment is preserved after...
//
// send toSerialize buffer
//
ByteBuffer wrappedBuffer(const_cast<char*>(toSerialize), count);
send(&wrappedBuffer);
//
// continue where we left before calling directSerialize
//
startMessage(_lastSegmentedMessageCommand, 0);
return true;
}
bool AbstractCodec::directDeserialize(ByteBuffer *existingBuffer, char* deserializeTo,
std::size_t elementCount, std::size_t elementSize)
{
return false;
// _socketBuffer == existingBuffer
/*
std::size_t bytesToBeDeserialized = elementCount*elementSize;
// TODO check if bytesToDeserialized < threshold that direct pays off?
_directPayloadRead = bytesToBeDeserialized;
_directBuffer = deserializeTo;
while (true)
{
// retrieve what's already in buffers
size_t availableBytes = min(_directPayloadRead, _socketBuffer->getRemaining());
existingBuffer->getArray(_directBuffer, availableBytes);
_directPayloadRead -= availableBytes;
if (_directPayloadRead == 0)
return true;
_directBuffer += availableBytes;
// subtract what was already processed
size_t pos = _socketBuffer->getPosition();
_storedPayloadSize -= pos -_storedPosition;
_storedPosition = pos;
// no more data and we have some payload left => read buffer
if (likely(_storedPayloadSize > 0))
{
size_t bytesToRead = std::min(_directPayloadRead, _storedPayloadSize);
processReadIntoDirectBuffer(bytesToRead);
// std::cout << "d: " << bytesToRead << std::endl;
_storedPayloadSize -= bytesToRead;
_directPayloadRead -= bytesToRead;
}
if (_directPayloadRead == 0)
return true;
_stage = PROCESS_HEADER;
processReadCached(true, UNDEFINED_STAGE, _directPayloadRead);
_storedPosition = _socketBuffer->getPosition();
_storedLimit = _socketBuffer->getLimit();
_socketBuffer->setLimit(
min(_storedPosition + _storedPayloadSize, _storedLimit)
);
}
return true;
*/
}
/*
void AbstractCodec::processReadIntoDirectBuffer(size_t bytesToRead)
{
while (bytesToRead > 0)
{
ssize_t bytesRead = recv(_channel, _directBuffer, bytesToRead, 0);
// std::cout << "d: " << bytesRead << std::endl;
if(unlikely(bytesRead<=0))
{
if (bytesRead<0)
{
int socketError = SOCKERRNO;
// interrupted or timeout
if (socketError == EINTR ||
socketError == EAGAIN ||
socketError == EWOULDBLOCK)
continue;
}
// error (disconnect, end-of-stream) detected
close();
THROW_BASE_EXCEPTION("bytesRead < 0");
return;
}
bytesToRead -= bytesRead;
_directBuffer += bytesRead;
}
}
*/
//
//
@@ -1018,10 +1165,16 @@ namespace epics {
{
try {
bac->processRead();
} catch (io_exception &e) {
} catch (connection_closed_exception &cce) {
// noop
} catch (std::exception &e) {
LOG(logLevelWarn,
"an exception caught while in receiveThread at %s:%d: %s",
"an exception caught while in sendThread at %s:%d: %s",
__FILE__, __LINE__, e.what());
} catch (...) {
LOG(logLevelError,
"unknown exception caught while in sendThread at %s:%d",
__FILE__, __LINE__);
}
}
@@ -1041,10 +1194,16 @@ namespace epics {
{
try {
bac->processWrite();
} catch (io_exception &e) {
} catch (connection_closed_exception &cce) {
// noop
} catch (std::exception &e) {
LOG(logLevelWarn,
"an exception caught while in sendThread at %s:%d: %s",
__FILE__, __LINE__, e.what());
} catch (...) {
LOG(logLevelError,
"unknown exception caught while in sendThread at %s:%d",
__FILE__, __LINE__);
}
}
@@ -1143,6 +1302,8 @@ namespace epics {
// NOTE: do not log here, you might override SOCKERRNO relevant to recv() operation above
// TODO winsock return 0 on disconnect (blocking socket) ?
if(unlikely(bytesSent<0)) {
int socketError = SOCKERRNO;
@@ -1150,6 +1311,8 @@ namespace epics {
// spurious EINTR check
if (socketError==SOCK_EINTR)
continue;
else if (socketError==SOCK_ENOBUFS)
return 0;
}
if (bytesSent > 0) {
@@ -1211,10 +1374,11 @@ namespace epics {
{
int socketError = SOCKERRNO;
// TODO SOCK_ENOBUFS, for read?
// interrupted or timeout
if (socketError == EINTR ||
if (socketError == SOCK_EINTR ||
socketError == EAGAIN ||
socketError == EWOULDBLOCK)
socketError == SOCK_EWOULDBLOCK)
continue;
}
@@ -1229,6 +1393,12 @@ namespace epics {
}
BlockingServerTCPTransportCodec::BlockingServerTCPTransportCodec(
Context::shared_pointer const & context,
SOCKET channel,
@@ -1372,7 +1542,7 @@ namespace epics {
int32_t sendBufferSize,
int32_t receiveBufferSize,
TransportClient::shared_pointer const & client,
epics::pvData::int8 remoteTransportRevision,
epics::pvData::int8 /*remoteTransportRevision*/,
float beaconInterval,
int16_t priority ) :
BlockingTCPTransportCodec(context, channel, responseHandler,
+17 -23
View File
@@ -244,7 +244,8 @@ namespace epics {
void alignData(std::size_t alignment);
void startMessage(
epics::pvData::int8 command,
std::size_t ensureCapacity);
std::size_t ensureCapacity = 0,
epics::pvData::int32 payloadSize = 0);
void putControlMessage(
epics::pvData::int8 command,
epics::pvData::int32 data);
@@ -265,10 +266,21 @@ namespace epics {
static std::size_t alignedValue(std::size_t value, std::size_t alignment);
bool directSerialize(
epics::pvData::ByteBuffer * /*existingBuffer*/,
const char* /*toSerialize*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/);
bool directDeserialize(epics::pvData::ByteBuffer * /*existingBuffer*/,
char* /*deserializeTo*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/);
protected:
virtual void sendBufferFull(int tries) = 0;
void send(epics::pvData::ByteBuffer *buffer);
virtual void sendBufferFull(int tries) = 0;
void send(epics::pvData::ByteBuffer *buffer);
void flushSendBuffer();
ReadMode _readMode;
@@ -487,24 +499,6 @@ namespace epics {
}
bool directSerialize(
epics::pvData::ByteBuffer * /*existingBuffer*/,
const char* /*toSerialize*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/)
{
// TODO !!!!
return false;
}
bool directDeserialize(epics::pvData::ByteBuffer * /*existingBuffer*/,
char* /*deserializeTo*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/) {
// TODO !!!
return false;
}
void flushSendQueue() { };
@@ -586,7 +580,7 @@ namespace epics {
public:
bool acquire(std::tr1::shared_ptr<TransportClient> const & client)
bool acquire(std::tr1::shared_ptr<TransportClient> const & /*client*/)
{
return false;
}
@@ -621,7 +615,7 @@ namespace epics {
// noop
}
bool verify(epics::pvData::int32 timeoutMs) {
bool verify(epics::pvData::int32 /*timeoutMs*/) {
TransportSender::shared_pointer transportSender =
std::tr1::dynamic_pointer_cast<TransportSender>(shared_from_this());
enqueueSendRequest(transportSender);
+1 -1
View File
@@ -122,7 +122,7 @@ namespace epics {
virtual ~TransportSendControl() {}
virtual void startMessage(epics::pvData::int8 command, std::size_t ensureCapacity) = 0;
virtual void startMessage(epics::pvData::int8 command, std::size_t ensureCapacity, epics::pvData::int32 payloadSize = 0) = 0;
virtual void endMessage() = 0;
virtual void flush(bool lastMessageCompleted) = 0;
+1 -1
View File
@@ -33,7 +33,7 @@ public:
void endMessage() {}
void flush(bool /*lastMessageCompleted*/) {}
void setRecipient(const osiSockAddr& /*sendTo*/) {}
void startMessage(epics::pvData::int8 /*command*/, std::size_t /*ensureCapacity*/) {}
void startMessage(epics::pvData::int8 /*command*/, std::size_t /*ensureCapacity*/, epics::pvData::int32 /*payloadSize*/) {}
void ensureBuffer(std::size_t /*size*/) {}
void alignBuffer(std::size_t /*alignment*/) {}
void flushSerializeBuffer() {}
+6 -9
View File
@@ -97,7 +97,7 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester
}
}
virtual void requestDone (const epics::pvData::Status &status, epics::pvData::PVStructure::shared_pointer const &pvResponse)
virtual void requestDone(const epics::pvData::Status &status, epics::pvData::PVStructure::shared_pointer const &pvResponse)
{
if (status.isSuccess())
{
@@ -112,23 +112,22 @@ class ChannelRPCRequesterImpl : public ChannelRPCRequester
Lock lock(m_pointerMutex);
response = pvResponse;
// this is OK since calle holds also owns it
// this is OK since calle holds reference to it
m_channelRPC.reset();
}
m_event.signal();
}
else
{
std::cerr << "[" << m_channelName << "] failed to RPC: " << status.toString() << std::endl;
{
Lock lock(m_pointerMutex);
// this is OK since caller holds also owns it
// this is OK since calle holds reference to it
m_channelRPC.reset();
}
}
m_event.signal();
}
/*
@@ -244,8 +243,6 @@ PVStructure::shared_pointer RPCClientImpl::request(PVStructure::shared_pointer p
bool allOK = true;
//ClientFactory::start();
if (m_connected || connect(timeOut))
{
shared_ptr<ChannelRPCRequesterImpl> rpcRequesterImpl(new ChannelRPCRequesterImpl(m_channel->getChannelName()));
@@ -275,8 +272,6 @@ PVStructure::shared_pointer RPCClientImpl::request(PVStructure::shared_pointer p
throw epics::pvAccess::RPCRequestException(Status::STATUSTYPE_ERROR, errMsg);
}
//ClientFactory::stop();
if (!allOK)
{
throw epics::pvAccess::RPCRequestException(Status::STATUSTYPE_ERROR, "RPC request failed");
@@ -289,6 +284,8 @@ PVStructure::shared_pointer RPCClientImpl::request(PVStructure::shared_pointer p
RPCClient::shared_pointer RPCClientFactory::create(const std::string & serviceName)
{
ClientFactory::start();
return RPCClient::shared_pointer(new RPCClientImpl(serviceName));
}
+6 -3
View File
@@ -19,6 +19,8 @@
# undef rpcClientEpicsExportSharedSymbols
#endif
#include <pv/rpcService.h>
#include <shareLib.h>
namespace epics
@@ -43,6 +45,7 @@ namespace pvAccess
* @param pvArgument the argument for the rpc
* @param timeout the time in seconds to wait for the response
* @return request response.
* @throws RPCRequestException exception thrown on error on timeout.
*/
virtual epics::pvData::PVStructure::shared_pointer request(epics::pvData::PVStructure::shared_pointer pvRequest,
double timeOut) = 0;
@@ -52,7 +55,7 @@ namespace pvAccess
class RPCClientFactory
class epicsShareClass RPCClientFactory
{
public:
/**
@@ -67,13 +70,13 @@ namespace pvAccess
/**
* Performs complete blocking RPC call, opening a channel and connecting to the
* service and sending the request.
* The PVStructure sent on connection is null.
*
* @param serviceName the name of the service to connect to
* @param request the request sent to the service
* @return the result of the RPC call.
* @throws RPCRequestException exception thrown on error on timeout.
*/
epics::pvData::PVStructure::shared_pointer sendRequest(const std::string & serviceName,
epicsShareExtern epics::pvData::PVStructure::shared_pointer sendRequest(const std::string & serviceName,
epics::pvData::PVStructure::shared_pointer request, double timeOut);
}
+4 -3
View File
@@ -67,6 +67,7 @@ static void stopPVAClientRegister(void)
}
}
epicsExportRegistrar(startPVAClientRegister);
epicsExportRegistrar(stopPVAClientRegister);
extern "C" {
epicsExportRegistrar(startPVAClientRegister);
epicsExportRegistrar(stopPVAClientRegister);
}
+4 -2
View File
@@ -125,5 +125,7 @@ static void stopPVAServerRegister(void)
}
}
epicsExportRegistrar(startPVAServerRegister);
epicsExportRegistrar(stopPVAServerRegister);
extern "C" {
epicsExportRegistrar(startPVAServerRegister);
epicsExportRegistrar(stopPVAServerRegister);
}
+4
View File
@@ -81,6 +81,10 @@ PROD_HOST += rpcServiceExample
rpcServiceExample_SRCS += rpcServiceExample.cpp
rpcServiceExample_LIBS += pvAccess pvData pvMB Com
PROD_HOST += rpcClientExample
rpcClientExample_SRCS += rpcClientExample.cpp
rpcClientExample_LIBS += pvAccess pvData pvMB Com
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
include $(TOP)/configure/RULES
+81 -1
View File
@@ -43,7 +43,7 @@ std::string ChannelAccessIFTest::TEST_ARRAY_CHANNEL_NAME = "testArray1";
int ChannelAccessIFTest::runAllTest() {
#ifdef ENABLE_STRESS_TESTS
testPlan(157);
testPlan(158);
#else
testPlan(152);
#endif
@@ -98,6 +98,7 @@ int ChannelAccessIFTest::runAllTest() {
test_channelArrayTestNoConnection();
#ifdef ENABLE_STRESS_TESTS
test_stressPutAndGetLargeArray();
test_stressConnectDisconnect();
test_stressConnectGetDisconnect();
test_stressMonitorAndProcess();
@@ -1990,6 +1991,85 @@ void ChannelAccessIFTest::test_channelArray_destroy() {
}
void ChannelAccessIFTest::test_stressPutAndGetLargeArray() {
testDiag("BEGIN TEST %s:", CURRENT_FUNCTION);
string request = "field(value)";
size_t minSize = 1;
size_t step = 25471;
size_t maxSize = 8*1024*1024; // 8MB
bool debug = false;
Channel::shared_pointer channel = syncCreateChannel(TEST_ARRAY_CHANNEL_NAME);
if (!channel.get()) {
testFail("%s: channel not created ", CURRENT_FUNCTION);
return;
}
SyncChannelPutRequesterImpl::shared_pointer putReq =
syncCreateChannelPut(channel, request, debug);
if (!putReq.get()) {
testFail("%s: creating a channel put failed ", CURRENT_FUNCTION);
return;
}
PVDoubleArray::shared_pointer value = putReq->getPVStructure()->getSubField<PVDoubleArray>("value");
if (!value.get()) {
testFail("%s: getting double array value field failed ", CURRENT_FUNCTION);
return;
}
PVDoubleArray::svector newdata;
for (size_t len = minSize; len <= maxSize; len+=step) {
//testDiag("%s: array size %zd", CURRENT_FUNCTION, len);
// prepare data
newdata.resize(len);
for (size_t i = 0; i < len; i++)
newdata[i] = i;
value->replace(freeze(newdata));
putReq->getBitSet()->set(value->getFieldOffset());
bool succStatus = putReq->syncPut(false, getTimeoutSec());
if (!succStatus) {
testFail("%s: sync put failed at array size %zd", CURRENT_FUNCTION, len);
return;
}
succStatus = putReq->syncGet(getTimeoutSec());
if (!succStatus) {
testFail("%s: sync get failed at array size %zd", CURRENT_FUNCTION, len);
return;
}
// length check
if (value->getLength() != len) {
testFail("%s: length does not math %zd != %zd", CURRENT_FUNCTION, len, value->getLength());
return;
}
// value check
PVDoubleArray::const_svector data(value->view());
for (size_t i = 0; i < len; i++) {
if (i != data[i]) // NOTE: floating-point value comparison without delta
testFail("%s: data slot %zd does not match %f != %f at array size %zd", CURRENT_FUNCTION, i, (double)i, data[i], len);
}
}
channel->destroy();
testOk(true, "%s: stress test put-and-get large array successfull", CURRENT_FUNCTION);
}
void ChannelAccessIFTest::test_stressConnectDisconnect() {
testDiag("BEGIN TEST %s:", CURRENT_FUNCTION);
+2
View File
@@ -141,6 +141,8 @@ class ChannelAccessIFTest {
void test_channelArrayTestNoConnection();
void test_stressPutAndGetLargeArray();
void test_stressConnectDisconnect();
void test_stressConnectGetDisconnect();
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvAccessCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <pv/pvData.h>
#include <pv/rpcClient.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
static StructureConstPtr requestStructure =
getFieldCreate()->createFieldBuilder()->
add("a", pvString)->
add("b", pvString)->
createStructure();
#define TIMEOUT 3.0
int main()
{
PVStructure::shared_pointer request = getPVDataCreate()->createPVStructure(requestStructure);
request->getSubField<PVString>("a")->put("3.14");
request->getSubField<PVString>("b")->put("2.71");
RPCClient::shared_pointer client = RPCClientFactory::create("sum");
try
{
PVStructure::shared_pointer result = client->request(request, TIMEOUT);
std::cout << *result << std::endl;
} catch (RPCRequestException &e)
{
std::cout << e.what() << std::endl;
return 1;
}
return 0;
}
+13 -19
View File
@@ -4,26 +4,16 @@
* in file LICENSE that is included with this distribution.
*/
#include <pv/convert.h>
#include <pv/pvData.h>
#include <pv/rpcServer.h>
using namespace epics::pvData;
using namespace epics::pvAccess;
static StructureConstPtr createResultField()
{
FieldCreatePtr fieldCreate = getFieldCreate();
StringArray fieldNames;
fieldNames.push_back("c");
FieldConstPtrArray fields;
fields.push_back(fieldCreate->createScalar(pvDouble));
return fieldCreate->createStructure(fieldNames, fields);
}
static StructureConstPtr resultStructure = createResultField();
static StructureConstPtr resultStructure =
getFieldCreate()->createFieldBuilder()->
add("c", pvDouble)->
createStructure();
class SumServiceImpl :
public RPCService
@@ -31,12 +21,16 @@ class SumServiceImpl :
PVStructure::shared_pointer request(PVStructure::shared_pointer const & args)
throw (RPCRequestException)
{
// TODO error handling
double a = atof(args->getStringField("a")->get().c_str());
double b = atof(args->getStringField("b")->get().c_str());
PVString::shared_pointer fa = args->getSubField<PVString>("a");
PVString::shared_pointer fb = args->getSubField<PVString>("b");
if (!fa || !fb)
throw RPCRequestException(Status::STATUSTYPE_ERROR, "'string a' and 'string b' fields required");
double a = atof(fa->get().c_str());
double b = atof(fb->get().c_str());
PVStructure::shared_pointer result = getPVDataCreate()->createPVStructure(resultStructure);
result->getDoubleField("c")->put(a+b);
result->getSubField<PVDouble>("c")->put(a+b);
return result;
}
};
+1 -1
View File
@@ -318,7 +318,7 @@ void SimADC::run()
cycle();
}
printf("SimADC shutdown\n");
//printf("SimADC shutdown\n");
}
SimADC::smart_pointer_type createSimADC(const std::string& name)
+3 -2
View File
@@ -77,8 +77,9 @@ class ChannelAccessIFRemoteTest: public ChannelAccessIFTest {
~ChannelAccessIFRemoteTest() {
m_serverContextAction.stop();
ClientFactory::stop();
structureChangedListeners.clear();
structureStore.clear();
// shutdown SIGSEG problems
epicsThreadSleep(2.0);
}
private:
+2 -9
View File
@@ -199,16 +199,9 @@ public:
epicsTimeStamp endTime;
epicsTimeGetCurrent(&endTime);
long seconds, nseconds;
double duration;
seconds = endTime.secPastEpoch - startTime.secPastEpoch;
nseconds = endTime.nsec - startTime.nsec;
duration = seconds + nseconds/1000000000.0;
double duration = epicsTime(endTime) - epicsTime(startTime);
double getPerSec = iterations*channels/duration;
double gbit = getPerSec*arraySize*sizeof(double)*8/(1000*1000*1000); // * bits / giga; NO, it's really 1000 and not 102:
double gbit = getPerSec*arraySize*sizeof(double)*8/(1000*1000*1000); // * bits / giga; NO, it's really 1000 and not 1024
if (verbose)
printf("%5.6f seconds, %.3f (x %d = %.3f) gets/s, data throughput %5.3f Gbits/s\n",
duration, iterations/duration, channels, getPerSec, gbit);
+9 -4
View File
@@ -2617,9 +2617,16 @@ void testServer(int timeToRun)
unregisterChannelProviderFactory(factory);
structureChangedListeners.clear();
structureStore.clear();
{
Lock guard(structureStoreMutex);
structureStore.clear();
}
ctx.reset();
unregisterChannelProviderFactory(factory);
shutdownSimADCs();
}
void testServerShutdown()
@@ -2690,8 +2697,6 @@ int main(int argc, char *argv[])
testServer(timeToRun);
shutdownSimADCs();
cout << "Done" << endl;
if (cleanupAndReport)