added longArrayGet and longArrayPut; much more testing
This commit is contained in:
@ -38,7 +38,7 @@
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 13-Nov-2013</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 20-Nov-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@ -46,7 +46,7 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131113.html">pvDatabaseCPP20131113.html</a>
|
||||
href= "pvDatabaseCPP_20131120.html">pvDatabaseCPP20131120.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
@ -79,17 +79,27 @@ V4 control system programming environment:<br />
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 13-Nov-2013 version of of pvDatabaseCPP.</p>
|
||||
<p>This is the 20-Nov-2013 version of of pvDatabaseCPP.</p>
|
||||
</p>
|
||||
<p>The previous version reported a problem with a queueSize of 1.
|
||||
Further thought showed that queueSize must be >= 2.
|
||||
This ensures that the locking between poll and dataChanged ensures that these two
|
||||
methods always use separate instances of pvStructure, changeBitSet, and overrunBitSet.</p>
|
||||
|
||||
<p>All channel methods except channelRPC, which is implemented
|
||||
by pvAccess, have been implemented.
|
||||
This project is ready for alpha users.
|
||||
</p>
|
||||
|
||||
<p>Since the last version the longArrayGet and longArrayPut examples were added.
|
||||
More testing for monitor queues and memory leaks was done.
|
||||
Everything looks good!!
|
||||
But there are still two unresolved problems:
|
||||
<dl>
|
||||
<dt>memory leak</dt>
|
||||
<dd>arrayPerformanceMain shows a slight memory leak at termination.</dd>
|
||||
<dt>channel destroy and recreate</dt>
|
||||
<dd>longArrayGet and longArrayPut fail if the channel is destroyed and
|
||||
immediately recreated.
|
||||
</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<p>Future enhancements in priority order:</p>
|
||||
<dl>
|
||||
<dt>Separate example that also has pvaSrv</dt>
|
||||
@ -1582,10 +1592,28 @@ where
|
||||
<dd>This creates the example using the remote channel provider.</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Array Performance</h2>
|
||||
<p>Two main programs are available for testing the performance of large
|
||||
arrays: arrayPerformanceMain and longArrayMonitorMain.
|
||||
Each has support for <b>-help</b>.</p>
|
||||
<h2>Array Performance and Memory Example</h2>
|
||||
<p>This section describes main programs that demonstrate performance
|
||||
of large arrays and can also be used to check for memory leaks.
|
||||
Checking for memory leaks can be accomplished by running the programs with valgrind
|
||||
or some other memory check program.
|
||||
</p>
|
||||
<h3>Brief Summary</h3>
|
||||
<p>The programs are:</p>
|
||||
<dl>
|
||||
<dt>arrayPerformanceMain</dt>
|
||||
<dd>This is server and also a configurable number of longArrayMonitor clients.
|
||||
The clients can use either the local or
|
||||
remote providers. The moitor code is the same code that is used by longArrayMonitorMain.
|
||||
</dd>
|
||||
<dt>longArrayMonitorMain</dt>
|
||||
<dd>Remote client that monitors the array served by arrayPerformanceMain.</dd>
|
||||
<dt>longArrayGetMain</dt>
|
||||
<dd>Remote client that uses channelGet to access the array served by arrayPerformanceMain.</dd>
|
||||
<dt>longArrayPutMain</dt>
|
||||
<dd>Remote client that uses channelPut to access the array served by arrayPerformanceMain.</dd>
|
||||
<dl>
|
||||
<p>Each has support for <b>-help</b>.</p>
|
||||
<pre>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP-md
|
||||
@ -1593,33 +1621,97 @@ mrk> bin/linux-x86_64/arrayPerformanceMain -help
|
||||
arrayPerformanceMain recordName size delay providerName nMonitor queueSize waitTime
|
||||
default
|
||||
arrayPerformance arrayPerformance 10000000 0.0001 local 1 2 0.0
|
||||
|
||||
mrk> bin/linux-x86_64/longArrayMonitorMain -help
|
||||
longArrayMonitorMain channelName queueSize waitTime
|
||||
default
|
||||
longArrayMonitorMain arrayPerformance 2 0.0
|
||||
|
||||
mrk> bin/linux-x86_64/longArrayGetMain -help
|
||||
longArrayGetMain channelName iterBetweenCreateChannel iterBetweenCreateChannelGet delayTime
|
||||
default
|
||||
longArrayGetMain arrayPerformance 0 0 1
|
||||
|
||||
mrk> bin/linux-x86_64/longArrayPutMain -help
|
||||
longArrayPutMain channelName arraySize iterBetweenCreateChannel iterBetweenCreateChannelPut delayTime
|
||||
default
|
||||
longArrayPutMain arrayPerformance 10 0 0 1
|
||||
|
||||
mrk>
|
||||
</pre>
|
||||
<h3>Example output</h3>
|
||||
<p><b>Note:</b> These may fail if run on a platform that does not have sufficent memory,</p>
|
||||
<p>To see an example just execute the following commands in four different terminal windows:</p>
|
||||
<pre>
|
||||
bin/linux/<arch>/arrayPerformanceMain
|
||||
bin/linux/<arch>/longArrayMonitorMain
|
||||
bin/linux/<arch>/longArrayGetMain
|
||||
bin/linux/<arch>/longArrayPutMain
|
||||
</pre>
|
||||
<p>Each program generates a report every second when it has somthing to report.
|
||||
Examples are:
|
||||
<pre>
|
||||
mrk> bin/linux-x86_64/arrayPerformanceMain
|
||||
arrayPerformance arrayPerformance 10000000 0.0001 local 1 2 0.0
|
||||
arrayPerformance arrayPerformance 10000000 0.0001 local 1 2 0
|
||||
...
|
||||
first 526 last 526 sum 5260000000 elements/sec 499.337million changed {1, 2} overrun {}
|
||||
first 527 last 527 sum 5270000000 elements/sec 568.729million changed {1, 2} overrun {}
|
||||
first 528 last 528 sum 5280000000 elements/sec 505.281million changed {1, 2} overrun {}
|
||||
first 529 last 529 sum 5290000000 elements/sec 506.33million changed {1, 2} overrun {}
|
||||
first 530 last 530 sum 5300000000 elements/sec 574.022million changed {1, 2} overrun {}
|
||||
arrayPerformance value 532 time 1.00839 iterations/sec 51.5672 elements/sec 515.672million
|
||||
first 531 last 531 sum 5310000000 elements/sec 484.185million changed {1, 2} overrun {}
|
||||
first 532 last 532 sum 5320000000 elements/sec 531.4million changed {1, 2} overrun {}
|
||||
first 533 last 533 sum 5330000000 elements/sec 428.229million changed {1, 2} overrun {}
|
||||
first 534 last 534 sum 5340000000 elements/sec 427.387million changed {1, 2} overrun {}
|
||||
first 535 last 535 sum 5350000000 elements/sec 443.669million changed {1, 2} overrun {}
|
||||
monitors/sec 66 first 131 last 131 changed {1, 2} overrun {} megaElements/sec 656.999
|
||||
arrayPerformance value 132 time 1.00486 Iterations/sec 65.681 megaElements/sec 656.81
|
||||
monitors/sec 66 first 197 last 197 changed {1, 2} overrun {} megaElements/sec 656.304
|
||||
arrayPerformance value 198 time 1.00563 Iterations/sec 65.6307 megaElements/sec 656.307
|
||||
monitors/sec 66 first 263 last 263 changed {1, 2} overrun {} megaElements/sec 654.824
|
||||
...
|
||||
</pre>
|
||||
<pre>
|
||||
mrk> bin/linux-x86_64/longArrayMonitorMain
|
||||
longArrayMonitorMain arrayPerformance 2 0
|
||||
...
|
||||
monitors/sec 6 first 2357 last 2357 changed {1, 2} overrun {} megaElements/sec 68.6406
|
||||
monitors/sec 13 first 2385 last 2385 changed {1, 2} overrun {} megaElements/sec 118.72
|
||||
monitors/sec 9 first 2418 last 2418 changed {1, 2} overrun {1, 2} megaElements/sec 85.0984
|
||||
...
|
||||
</pre>
|
||||
<pre>
|
||||
mrk> bin/linux-x86_64/longArrayPutMain
|
||||
longArrayPutMain arrayPerformance 10 0 0 1
|
||||
...
|
||||
put numChannelPut 0 time 1.00148 Elements/sec 79.8819
|
||||
put numChannelPut 1 time 1.00176 Elements/sec 79.8598
|
||||
...
|
||||
</pre>
|
||||
<pre>
|
||||
mrk> bin/linux-x86_64/longArrayGetMain
|
||||
longArrayGetMain arrayPerformance 0 0 1
|
||||
...
|
||||
get kiloElements/sec 7384.61
|
||||
get kiloElements/sec 8726.34
|
||||
...
|
||||
</pre>
|
||||
|
||||
<h3>arrayPerformance</h3>
|
||||
<p>The arguments for arrayPerforamanceMain are:</p>
|
||||
<dl>
|
||||
<dt>recordName</dt>
|
||||
<dd>The name for the arrayPerform record.</dd>
|
||||
<dt>size</dt>
|
||||
<dd>The size for the long array of the value field.</dd>
|
||||
<dt>delay</dt>
|
||||
<dd>The time in seconds to sleep after each iteration.</dd>
|
||||
<dt>providerName</dt>
|
||||
<dd>The name of the channel provider for the longArrayMonitors
|
||||
created by the main program. This must be either <b>local</b>
|
||||
or <b>pvAccess</b>.
|
||||
</dd>
|
||||
<dt>nMonitor</dt>
|
||||
<dd>The number of longArrayMonitors to create.</dd>
|
||||
<dt>queueSize</dt>
|
||||
<dd>The queueSize for the element queue.
|
||||
A value less than 1 will become 1.
|
||||
</dd>
|
||||
<dt>waitTime</dt>
|
||||
<dd>The time that longArrayMonitor will sleep after poll returns a monitorElement.</dd>
|
||||
</dl>
|
||||
<p>
|
||||
This creates a PVRecord that has the structure:.
|
||||
arrayPerformance creates a PVRecord that has the structure:.
|
||||
<pre>
|
||||
recordName
|
||||
long[] value
|
||||
@ -1631,7 +1723,7 @@ Thus it holds an array of 64 bit integers.</p>
|
||||
until the record is destroyed executing the following algorithm:</p>
|
||||
<dl>
|
||||
<dt>report</dt>
|
||||
<dd>At least once a second it produces a report.
|
||||
<dd>Once a second it produces a report.
|
||||
In the above example output each line starting with
|
||||
<b>ArrayPerformance</b> is an arrayPerformance report.
|
||||
</dd>
|
||||
@ -1655,40 +1747,66 @@ until the record is destroyed executing the following algorithm:</p>
|
||||
<dt>delay</dt>
|
||||
<dd>If delay is greater than zero epicsThreadSleep is called.</dd>
|
||||
</dl>
|
||||
<p>The arguments for arrayPerforamanceMain are:</p>
|
||||
<dl>
|
||||
<dt>recordName</dt>
|
||||
<dd>The name for the arrayPerform record.</dd>
|
||||
<dt>size</dt>
|
||||
<dd>The size for the long array of the value field.</dd>
|
||||
<dt>delay</dt>
|
||||
<dd>The time in seconds to sleep after each iteration.</dd>
|
||||
<dt>providerName</dt>
|
||||
<dd>The name of the channel provider for the longArrayMonitors
|
||||
created by the main program. This must be either <b>local</b>
|
||||
or <b>pvAccess</b>.
|
||||
</dd>
|
||||
<dt>nMonitor</dt>
|
||||
<dd>The number of longArrayMonitors to create.</dd>
|
||||
<dt>queueSize</dt>
|
||||
<dd>The queueSize for the element queue.
|
||||
A value less than 1 will become 1.
|
||||
</dd>
|
||||
<dt>waitTime</dt>
|
||||
<dd>The time that longArrayMonitor will sleep after poll returns a monitorElement.</dd>
|
||||
</dl>
|
||||
<h3>longArrayMonitor</h3>
|
||||
<p>This is a pvAccess client that monitors an arrayPerformance record.
|
||||
It generates a report for each monitor event.
|
||||
In the example output shown above each line starting with <b>first</b>
|
||||
is a report.</p>
|
||||
It generates a report every second showing how many elements has received.
|
||||
For every monitor it also checks that the number of alements is >0 and the
|
||||
the first element equals the last element. It reports an error if either
|
||||
of these conditions is not true.</p>
|
||||
<p>The arguments for longArrayMonitorMain are:</p>
|
||||
<dl>
|
||||
<dt>channelName</dt>
|
||||
<dd>The name for the arrayPerform record.</dd>
|
||||
<dt>queueSize</dt>
|
||||
<dd>The queueSize. Note that any size <2 is made 2.</dd>
|
||||
<dt>waitTime</dt>
|
||||
<dd>The time to wait after a poll request returns a monitorElement.
|
||||
This can be used to force an overrun of the client even if there is no
|
||||
overrun on the server.</dd>
|
||||
</dl>
|
||||
<h3>longArrayGet</h3>
|
||||
<p>This is a pvAccess client that uses channelGet to access an arrayPerformance record.
|
||||
Every second it produces a report.</p>
|
||||
|
||||
<p>The arguments for longArrayGetMain are:</p>
|
||||
<dl>
|
||||
<dt>channelName</dt>
|
||||
<dd>The name for the arrayPerform record.</dd>
|
||||
<dt>iterBetweenCreateChannel</dt>
|
||||
<dd>The number of iterations between destroying and recreating the channel.
|
||||
A value of 0 means never destroy and recreate.
|
||||
</dd>
|
||||
<dt>iterBetweenCreateChannelGet</dt>
|
||||
<dd>The number of iterations between destroying and recreating the channelGet.
|
||||
A value of 0 means never destroy and recreate.
|
||||
</dd>
|
||||
<dt>delayTime</dt>
|
||||
<dd>The time to dalay between gets.</dd>
|
||||
</dl>
|
||||
<h3>longArrayPut</h3>
|
||||
<p>This is a pvAccess client that uses channelPut to access an arrayPerformance record.
|
||||
Every second it produces a report.</p>
|
||||
|
||||
<p>The arguments for longArrayPutMain are:</p>
|
||||
<dl>
|
||||
<dt>channelName</dt>
|
||||
<dd>The name for the arrayPerform record.</dd>
|
||||
<dt>arraySize</dt>
|
||||
<dd>The capacity and length of the array to put to the server.</dd>
|
||||
<dt>iterBetweenCreateChannel</dt>
|
||||
<dd>The number of iterations between destroying and recreating the channel.
|
||||
A value of 0 means never destroy and recreate.
|
||||
</dd>
|
||||
<dt>iterBetweenCreateChannelPut</dt>
|
||||
<dd>The number of iterations between destroying and recreating the channelPut.
|
||||
A value of 0 means never destroy and recreate.
|
||||
</dd>
|
||||
<dt>delayTime</dt>
|
||||
<dd>The time to dalay between gets.</dd>
|
||||
</dl>
|
||||
|
||||
<h3>Some results</h3>
|
||||
<h4>array performance</h4>
|
||||
<p>The results were from my laptop.
|
||||
It has a 2.2Ghz intel core i7 with 4Gbytes of memory.
|
||||
The operating system is linux fedora 16.</p>
|
||||
@ -1724,6 +1842,21 @@ The next section has an example that demonstrates what happens.
|
||||
Note that if the array size is small enough to fit in the local cache then running longArrayMonitor
|
||||
has almost no effect of arrayPerforance.
|
||||
</p>
|
||||
<h4>memory leaks</h4>
|
||||
<p>Running longArrayMonitorMain, longArrayPutMain, and longArrayGetMain
|
||||
under valgrind shows no memory leaks.</p>
|
||||
<p>arrayPerformanceMain shows the following:</p>
|
||||
<pre>
|
||||
==9125== LEAK SUMMARY:
|
||||
==9125== definitely lost: 0 bytes in 0 blocks
|
||||
==9125== indirectly lost: 0 bytes in 0 blocks
|
||||
==9125== possibly lost: 576 bytes in 2 blocks
|
||||
</pre>
|
||||
<p>The possibly leaked is either 1 or 2 blocks.
|
||||
It seems to be the same if clients are connected.
|
||||
</p>
|
||||
<h4>iterBetweenCreateChannel</h4>
|
||||
<p>If this is not zero then the attempt to destroy and recreate the channel fails.</p>
|
||||
<h2>Vector Performance</h2>
|
||||
<p>This example demonstrates how array size effects performance.
|
||||
The example is run as:</p>
|
||||
|
1936
documentation/pvDatabaseCPP_20131120.html
Normal file
1936
documentation/pvDatabaseCPP_20131120.html
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,16 @@ longArrayMonitorMain_SRCS += longArrayMonitorMain.cpp
|
||||
longArrayMonitorMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
longArrayMonitorMain_LIBS += pvDatabaseExample
|
||||
|
||||
PROD_HOST += longArrayGetMain
|
||||
longArrayGetMain_SRCS += longArrayGetMain.cpp
|
||||
longArrayGetMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
longArrayGetMain_LIBS += pvDatabaseExample
|
||||
|
||||
PROD_HOST += longArrayPutMain
|
||||
longArrayPutMain_SRCS += longArrayPutMain.cpp
|
||||
longArrayPutMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
longArrayPutMain_LIBS += pvDatabaseExample
|
||||
|
||||
PROD_HOST += vectorPerformanceMain
|
||||
vectorPerformanceMain_SRCS += vectorPerformanceMain.cpp
|
||||
vectorPerformanceMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
|
86
example/arrayPerformance/longArrayGetMain.cpp
Normal file
86
example/arrayPerformance/longArrayGetMain.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*longArrayGetMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.08.10
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/arrayPerformance.h>
|
||||
#include <pv/longArrayGet.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/clientFactory.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
String channelName("arrayPerformance");
|
||||
int iterBetweenCreateChannel = 0;
|
||||
int iterBetweenCreateChannelGet = 0;
|
||||
double delayTime = 1.0;
|
||||
if(argc==2 && String(argv[1])==String("-help")) {
|
||||
cout << "longArrayGetMain channelName ";
|
||||
cout << "iterBetweenCreateChannel iterBetweenCreateChannelGet delayTime" << endl;
|
||||
cout << "default" << endl;
|
||||
cout << "longArrayGetMain " << channelName << " ";
|
||||
cout << iterBetweenCreateChannel << " ";
|
||||
cout << iterBetweenCreateChannelGet << " ";
|
||||
cout << delayTime << endl;
|
||||
return 0;
|
||||
}
|
||||
ClientFactory::start();
|
||||
if(argc>1) channelName = argv[1];
|
||||
if(argc>2) iterBetweenCreateChannel = strtol(argv[2],0,0);
|
||||
if(argc>3) iterBetweenCreateChannelGet = strtol(argv[3],0,0);
|
||||
if(argc>4) delayTime = atof(argv[4]);
|
||||
cout << "longArrayGetMain " << channelName << " ";
|
||||
cout << iterBetweenCreateChannel << " ";
|
||||
cout << iterBetweenCreateChannelGet << " ";
|
||||
cout << delayTime << endl;
|
||||
LongArrayGetPtr longArrayGet
|
||||
= LongArrayGet::create(
|
||||
"pvAccess",
|
||||
channelName,
|
||||
iterBetweenCreateChannel,
|
||||
iterBetweenCreateChannelGet,
|
||||
delayTime);
|
||||
cout << "longArrayGet\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
longArrayGet->destroy();
|
||||
longArrayGet.reset();
|
||||
double xxx = 1.0;
|
||||
if(xxx<delayTime) xxx = delayTime;
|
||||
ClientFactory::stop();
|
||||
epicsThreadSleep(xxx);
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,10 +66,10 @@ int main(int argc,char *argv[])
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
ClientFactory::stop();
|
||||
epicsThreadSleep(.1);
|
||||
longArrayMonitor->destroy();
|
||||
longArrayMonitor.reset();
|
||||
ClientFactory::stop();
|
||||
epicsThreadSleep(1.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
92
example/arrayPerformance/longArrayPutMain.cpp
Normal file
92
example/arrayPerformance/longArrayPutMain.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*longArrayPutMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.08.10
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/arrayPerformance.h>
|
||||
#include <pv/longArrayPut.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/clientFactory.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
String channelName("arrayPerformance");
|
||||
size_t arraySize = 10;
|
||||
int iterBetweenCreateChannel = 0;
|
||||
int iterBetweenCreateChannelPut = 0;
|
||||
double delayTime = 1.0;
|
||||
if(argc==2 && String(argv[1])==String("-help")) {
|
||||
cout << "longArrayPutMain channelName arraySize ";
|
||||
cout << "iterBetweenCreateChannel iterBetweenCreateChannelPut delayTime" << endl;
|
||||
cout << "default" << endl;
|
||||
cout << "longArrayPutMain " << channelName << " ";
|
||||
cout << arraySize << " ";
|
||||
cout << iterBetweenCreateChannel << " ";
|
||||
cout << iterBetweenCreateChannelPut << " ";
|
||||
cout << delayTime << endl;
|
||||
return 0;
|
||||
}
|
||||
ClientFactory::start();
|
||||
if(argc>1) channelName = argv[1];
|
||||
if(argc>2) arraySize = strtoul(argv[2],0,0);
|
||||
if(argc>3) iterBetweenCreateChannel = strtol(argv[3],0,0);
|
||||
if(argc>4) iterBetweenCreateChannelPut = strtol(argv[4],0,0);
|
||||
if(argc>5) delayTime = atof(argv[5]);
|
||||
cout << "longArrayPutMain " << channelName << " ";
|
||||
cout << arraySize << " ";
|
||||
cout << iterBetweenCreateChannel << " ";
|
||||
cout << iterBetweenCreateChannelPut << " ";
|
||||
cout << delayTime << endl;
|
||||
LongArrayPutPtr longArrayPut
|
||||
= LongArrayPut::create(
|
||||
"pvAccess",
|
||||
channelName,
|
||||
arraySize,
|
||||
iterBetweenCreateChannel,
|
||||
iterBetweenCreateChannelPut,
|
||||
delayTime);
|
||||
cout << "longArrayPut\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
longArrayPut->destroy();
|
||||
longArrayPut.reset();
|
||||
double xxx = 1.0;
|
||||
if(xxx<delayTime) xxx = delayTime;
|
||||
epicsThreadSleep(xxx);
|
||||
ClientFactory::stop();
|
||||
epicsThreadSleep(1.0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ INC+= arrayPerformance.h
|
||||
LIBSRCS += arrayPerformance.cpp
|
||||
INC+= longArrayMonitor.h
|
||||
LIBSRCS += longArrayMonitor.cpp
|
||||
INC+= longArrayGet.h
|
||||
LIBSRCS += longArrayGet.cpp
|
||||
INC+= longArrayPut.h
|
||||
LIBSRCS += longArrayPut.cpp
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
@ -143,15 +143,36 @@ void ArrayPerformanceThread::run()
|
||||
if(diff>=1.0) {
|
||||
ostringstream out;
|
||||
out << "arrayPerformance value " << value;
|
||||
out << " time " << diff;
|
||||
out << " time " << diff ;
|
||||
double iterations = nSinceLastReport;
|
||||
iterations /= diff;
|
||||
out << " iterations/sec " << iterations;
|
||||
if(iterations>10.0e9) {
|
||||
iterations /= 1e9;
|
||||
out << " gigaIterations/sec " << iterations;
|
||||
} else if(iterations>10.0e6) {
|
||||
iterations /= 1e6;
|
||||
out << " megaIterations/sec " << iterations;
|
||||
} else if(iterations>10.0e3) {
|
||||
iterations /= 1e3;
|
||||
out << " kiloIterations/sec " << iterations;
|
||||
} else {
|
||||
out << " Iterations/sec " << iterations;
|
||||
}
|
||||
double elementSize = arrayPerformance->size;
|
||||
double elementsPerSecond = elementSize*nSinceLastReport;
|
||||
elementsPerSecond /= diff;
|
||||
elementsPerSecond /= 1e6;
|
||||
out << " elements/sec " << elementsPerSecond << "million";
|
||||
if(elementsPerSecond>10.0e9) {
|
||||
elementsPerSecond /= 1e9;
|
||||
out << " gigaElements/sec " << elementsPerSecond;
|
||||
} else if(elementsPerSecond>10.0e6) {
|
||||
elementsPerSecond /= 1e6;
|
||||
out << " megaElements/sec " << elementsPerSecond;
|
||||
} else if(elementsPerSecond>10.0e3) {
|
||||
elementsPerSecond /= 1e3;
|
||||
out << " kiloElements/sec " << elementsPerSecond;
|
||||
} else {
|
||||
out << " Elements/sec " << elementsPerSecond;
|
||||
}
|
||||
cout << out.str() << endl;
|
||||
timeStampLast = timeStamp;
|
||||
nSinceLastReport = 0;
|
||||
|
381
example/src/arrayPerformance/longArrayGet.cpp
Normal file
381
example/src/arrayPerformance/longArrayGet.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
/* longArrayGet.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.08.09
|
||||
*/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/longArrayGet.h>
|
||||
#include <pv/caProvider.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::ostringstream;
|
||||
|
||||
static String requesterName("longArrayGet");
|
||||
static String request("value,timeStamp,alarm");
|
||||
static epics::pvData::Mutex printMutex;
|
||||
|
||||
class LongArrayChannelGet :
|
||||
virtual public ChannelRequester,
|
||||
virtual public ChannelGetRequester,
|
||||
public std::tr1::enable_shared_from_this<LongArrayChannelGet>,
|
||||
public epicsThreadRunable
|
||||
{
|
||||
public:
|
||||
LongArrayChannelGet(
|
||||
String providerName,
|
||||
String channelName,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelGet,
|
||||
double delayTime)
|
||||
: providerName(providerName),
|
||||
channelName(channelName),
|
||||
iterBetweenCreateChannel(iterBetweenCreateChannel),
|
||||
iterBetweenCreateChannelGet(iterBetweenCreateChannelGet),
|
||||
delayTime(delayTime),
|
||||
isDestroyed(false),
|
||||
runReturned(false),
|
||||
threadName("longArrayGet")
|
||||
{}
|
||||
virtual ~LongArrayChannelGet(){}
|
||||
bool init();
|
||||
virtual void destroy();
|
||||
virtual void run();
|
||||
virtual String getRequesterName() { return requesterName;}
|
||||
virtual void message(String const & message, MessageType messageType)
|
||||
{
|
||||
Lock guard(printMutex);
|
||||
cout << requesterName << " message " << message << endl;
|
||||
}
|
||||
virtual void channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel);
|
||||
virtual void channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState);
|
||||
virtual void channelGetConnect(
|
||||
Status const & status,
|
||||
ChannelGet::shared_pointer const & channelGet,
|
||||
PVStructurePtr const &pvStructure,
|
||||
BitSetPtr const &bitSet);
|
||||
virtual void getDone(Status const & status);
|
||||
private:
|
||||
LongArrayChannelGetPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
size_t checkResult();
|
||||
String providerName;
|
||||
String channelName;
|
||||
int iterBetweenCreateChannel;
|
||||
int iterBetweenCreateChannelGet;
|
||||
double delayTime;
|
||||
bool isDestroyed;
|
||||
bool runReturned;
|
||||
epics::pvData::String threadName;
|
||||
Status status;
|
||||
Event event;
|
||||
Mutex mutex;
|
||||
std::auto_ptr<epicsThread> thread;
|
||||
Channel::shared_pointer channel;
|
||||
ChannelGet::shared_pointer channelGet;
|
||||
PVStructurePtr pvStructure;
|
||||
BitSetPtr bitSet;
|
||||
};
|
||||
|
||||
bool LongArrayChannelGet::init()
|
||||
{
|
||||
ChannelProvider::shared_pointer channelProvider =
|
||||
getChannelAccess()->getProvider(providerName);
|
||||
if(channelProvider==NULL) {
|
||||
cout << "provider " << providerName << " not found" << endl;
|
||||
return false;
|
||||
}
|
||||
channel = channelProvider->createChannel(channelName,getPtrSelf(),0);
|
||||
event.wait();
|
||||
channelProvider.reset();
|
||||
if(!status.isOK()) return false;
|
||||
CreateRequest::shared_pointer createRequest = CreateRequest::create();
|
||||
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
||||
if(pvRequest==NULL) {
|
||||
cout << "request logic error " << createRequest->getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
channelGet = channel->createChannelGet(getPtrSelf(),pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) return false;
|
||||
thread = std::auto_ptr<epicsThread>(new epicsThread(
|
||||
*this,
|
||||
threadName.c_str(),
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
epicsThreadPriorityLow));
|
||||
thread->start();
|
||||
event.signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LongArrayChannelGet::destroy()
|
||||
{
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
event.signal();
|
||||
while(true) {
|
||||
if(runReturned) break;
|
||||
epicsThreadSleep(.01);
|
||||
}
|
||||
thread->exitWait();
|
||||
channel->destroy();
|
||||
channelGet.reset();
|
||||
channel.reset();
|
||||
}
|
||||
|
||||
void LongArrayChannelGet::channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel)
|
||||
{
|
||||
if(!status.isOK()) message(status.getMessage(),errorMessage);
|
||||
this->status = status;
|
||||
this->channel = channel;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void LongArrayChannelGet::channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState)
|
||||
{
|
||||
MessageType messageType =
|
||||
(connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
|
||||
message("channelStateChange",messageType);
|
||||
}
|
||||
|
||||
|
||||
void LongArrayChannelGet::channelGetConnect(
|
||||
Status const & status,
|
||||
ChannelGet::shared_pointer const & channelGet,
|
||||
PVStructurePtr const &pvStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
this->status = status;
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
event.signal();
|
||||
return;
|
||||
}
|
||||
this->channelGet = channelGet;
|
||||
this->pvStructure = pvStructure;
|
||||
this->bitSet = bitSet;
|
||||
bool structureOK(true);
|
||||
PVFieldPtr pvField = pvStructure->getSubField("timeStamp");
|
||||
if(pvField==NULL) structureOK = false;
|
||||
pvField = pvStructure->getSubField("value");
|
||||
if(pvField==NULL) {
|
||||
structureOK = false;
|
||||
} else {
|
||||
FieldConstPtr field = pvField->getField();
|
||||
if(field->getType()!=scalarArray) {
|
||||
structureOK = false;
|
||||
} else {
|
||||
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
|
||||
if(scalarArray->getElementType()!=pvLong) structureOK = false;
|
||||
}
|
||||
}
|
||||
if(!structureOK) {
|
||||
String mess("channelGetConnect: illegal structure");
|
||||
message(mess,errorMessage);
|
||||
this->status = Status(Status::STATUSTYPE_ERROR,mess);
|
||||
}
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void LongArrayChannelGet::run()
|
||||
{
|
||||
while(true) {
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
TimeStamp timeStamp;
|
||||
TimeStamp timeStampLast;
|
||||
timeStampLast.getCurrent();
|
||||
int numChannelGet = 0;
|
||||
int numChannelCreate = 0;
|
||||
size_t nElements = 0;
|
||||
while(true) {
|
||||
channelGet->get(false);
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
size_t latestSize = checkResult();
|
||||
nElements += latestSize;
|
||||
timeStamp.getCurrent();
|
||||
double diff = TimeStamp::diff(timeStamp,timeStampLast);
|
||||
if(diff>=1.0) {
|
||||
ostringstream out;
|
||||
out << "get";
|
||||
double elementsPerSec = nElements;
|
||||
elementsPerSec /= diff;
|
||||
if(elementsPerSec>10.0e9) {
|
||||
elementsPerSec /= 1e9;
|
||||
out << " gigaElements/sec " << elementsPerSec;
|
||||
} else if(elementsPerSec>10.0e6) {
|
||||
elementsPerSec /= 1e6;
|
||||
out << " megaElements/sec " << elementsPerSec;
|
||||
} else if(elementsPerSec>10.0e3) {
|
||||
elementsPerSec /= 1e3;
|
||||
out << " kiloElements/sec " << elementsPerSec;
|
||||
} else {
|
||||
out << " Elements/sec " << elementsPerSec;
|
||||
}
|
||||
cout << out.str() << endl;
|
||||
timeStampLast = timeStamp;
|
||||
nElements = 0;
|
||||
}
|
||||
if(delayTime>0.0) epicsThreadSleep(delayTime);
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
++numChannelCreate;
|
||||
bool createGet = false;
|
||||
if(iterBetweenCreateChannel!=0) {
|
||||
if(numChannelCreate>=iterBetweenCreateChannel) {
|
||||
channel->destroy();
|
||||
ChannelProvider::shared_pointer channelProvider =
|
||||
getChannelAccess()->getProvider(providerName);
|
||||
channel = channelProvider->createChannel(
|
||||
channelName,getPtrSelf(),0);
|
||||
event.wait();
|
||||
channelProvider.reset();
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
return;
|
||||
}
|
||||
cout<< "createChannel success" << endl;
|
||||
createGet = true;
|
||||
numChannelCreate = 0;
|
||||
numChannelGet = 0;
|
||||
}
|
||||
}
|
||||
++numChannelGet;
|
||||
if(iterBetweenCreateChannelGet!=0) {
|
||||
if(numChannelGet>=iterBetweenCreateChannelGet) createGet = true;
|
||||
}
|
||||
if(createGet) {
|
||||
numChannelGet = 0;
|
||||
channelGet->destroy();
|
||||
CreateRequest::shared_pointer createRequest = CreateRequest::create();
|
||||
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
||||
if(pvRequest==NULL) {
|
||||
cout << "request logic error " << createRequest->getMessage() << endl;
|
||||
return ;
|
||||
}
|
||||
channelGet = channel->createChannelGet(getPtrSelf(),pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
return;
|
||||
}
|
||||
cout<< "createChannelGet success" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LongArrayChannelGet::getDone(Status const & status)
|
||||
{
|
||||
event.signal();
|
||||
}
|
||||
|
||||
size_t LongArrayChannelGet::checkResult()
|
||||
{
|
||||
PVLongArrayPtr pvValue;
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
return 0;
|
||||
}
|
||||
pvValue = dynamic_pointer_cast<PVLongArray>(pvStructure->getSubField("value"));
|
||||
if(!bitSet->get(pvValue->getFieldOffset())) {
|
||||
return 0;
|
||||
}
|
||||
bitSet->clear();
|
||||
shared_vector<const int64> data = pvValue->view();
|
||||
if(data.size()>0) {
|
||||
int64 first = data[0];
|
||||
int64 last = data[data.size()-1];
|
||||
if(first!=last) {
|
||||
cout << "error first=" << first << " last=" << last << endl;
|
||||
}
|
||||
}
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
||||
LongArrayGetPtr LongArrayGet::create(
|
||||
String const &providerName,
|
||||
String const & channelName,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelGet,
|
||||
double delayTime)
|
||||
{
|
||||
LongArrayGetPtr longArrayGet(
|
||||
new LongArrayGet(
|
||||
providerName,
|
||||
channelName,
|
||||
iterBetweenCreateChannel,
|
||||
iterBetweenCreateChannelGet,
|
||||
delayTime));
|
||||
if(!longArrayGet->init()) longArrayGet.reset();
|
||||
return longArrayGet;
|
||||
}
|
||||
|
||||
LongArrayGet::LongArrayGet(
|
||||
String const &providerName,
|
||||
String const & channelName,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelGet,
|
||||
double delayTime)
|
||||
: providerName(providerName),
|
||||
channelName(channelName),
|
||||
iterBetweenCreateChannel(iterBetweenCreateChannel),
|
||||
iterBetweenCreateChannelGet(iterBetweenCreateChannelGet),
|
||||
delayTime(delayTime)
|
||||
{}
|
||||
|
||||
|
||||
LongArrayGet::~LongArrayGet() {}
|
||||
|
||||
bool LongArrayGet::init()
|
||||
{
|
||||
longArrayChannelGet = LongArrayChannelGetPtr(new LongArrayChannelGet(
|
||||
providerName,
|
||||
channelName,
|
||||
iterBetweenCreateChannel,
|
||||
iterBetweenCreateChannelGet,
|
||||
delayTime));
|
||||
return longArrayChannelGet->init();
|
||||
}
|
||||
|
||||
void LongArrayGet::destroy()
|
||||
{
|
||||
longArrayChannelGet->destroy();
|
||||
longArrayChannelGet.reset();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
68
example/src/arrayPerformance/longArrayGet.h
Normal file
68
example/src/arrayPerformance/longArrayGet.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* longArrayGet.h */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.08.09
|
||||
*/
|
||||
#ifndef LONGARRAYGET_H
|
||||
#define LONGARRAYGET_H
|
||||
|
||||
#include <pv/event.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/pvAccess.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class LongArrayGet;
|
||||
typedef std::tr1::shared_ptr<LongArrayGet> LongArrayGetPtr;
|
||||
|
||||
|
||||
class LongArrayChannelGet;
|
||||
typedef std::tr1::shared_ptr<LongArrayChannelGet> LongArrayChannelGetPtr;
|
||||
|
||||
class LongArrayGet :
|
||||
public std::tr1::enable_shared_from_this<LongArrayGet>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(LongArrayGet);
|
||||
static LongArrayGetPtr create(
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName,
|
||||
int iterBetweenCreateChannel = 0,
|
||||
int iterBetweenCreateChannelGet = 0,
|
||||
double delayTime = 0.0);
|
||||
~LongArrayGet();
|
||||
void destroy();
|
||||
private:
|
||||
LongArrayGetPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
LongArrayGet(
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName,
|
||||
int iterBetweenCreateChannel = 0,
|
||||
int iterBetweenCreateChannelGet = 0,
|
||||
double delayTime = 0.0);
|
||||
bool init();
|
||||
|
||||
epics::pvData::String providerName;
|
||||
epics::pvData::String channelName;
|
||||
int iterBetweenCreateChannel;
|
||||
int iterBetweenCreateChannelGet;
|
||||
double delayTime;
|
||||
LongArrayChannelGetPtr longArrayChannelGet;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* LONGARRAYGET_H */
|
@ -21,6 +21,7 @@ using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::ostringstream;
|
||||
|
||||
static String requesterName("longArrayMonitor");
|
||||
|
||||
@ -86,7 +87,6 @@ public:
|
||||
virtual void monitorEvent(MonitorPtr const & monitor);
|
||||
virtual void unlisten(MonitorPtr const & monitor);
|
||||
private:
|
||||
void handleMonitor();
|
||||
LongArrayMonitorPtr longArrayMonitor;
|
||||
double waitTime;
|
||||
bool isDestroyed;
|
||||
@ -160,6 +160,8 @@ void LAMMonitorRequester::run()
|
||||
TimeStamp timeStamp;
|
||||
TimeStamp timeStampLast;
|
||||
timeStampLast.getCurrent();
|
||||
size_t nElements = 0;
|
||||
int nSinceLastReport = 0;
|
||||
while(true) {
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
@ -181,25 +183,45 @@ void LAMMonitorRequester::run()
|
||||
pvValue = dynamic_pointer_cast<PVLongArray>(pvStructure->getSubField("value"));
|
||||
shared_vector<const int64> data = pvValue->view();
|
||||
if(data.size()>0) {
|
||||
nElements += data.size();
|
||||
int64 first = data[0];
|
||||
int64 last = data[data.size()-1];
|
||||
int64 sum = 0;
|
||||
for(size_t i=0; i<data.size(); ++i) sum += data[i];
|
||||
if(first!=last) {
|
||||
cout << "error first=" << first << " last=" << last << endl;
|
||||
}
|
||||
double diff = TimeStamp::diff(timeStamp,timeStampLast);
|
||||
double elementsPerSecond = data.size();
|
||||
elementsPerSecond = 1e-6*elementsPerSecond/diff;
|
||||
cout << "first " << first << " last " << last << " sum " << sum;
|
||||
cout << " elements/sec " << elementsPerSecond << "million";
|
||||
BitSetPtr changed = monitorElement->changedBitSet;
|
||||
BitSetPtr overrun = monitorElement->overrunBitSet;
|
||||
String buffer;
|
||||
changed->toString(&buffer);
|
||||
cout << " changed " << buffer;
|
||||
buffer.clear();
|
||||
overrun->toString(&buffer);
|
||||
cout << " overrun " << buffer;
|
||||
cout << endl;
|
||||
timeStampLast = timeStamp;
|
||||
if(diff>=1.0) {
|
||||
ostringstream out;
|
||||
out << " monitors/sec " << nSinceLastReport << " ";
|
||||
out << "first " << first << " last " << last ;
|
||||
BitSetPtr changed = monitorElement->changedBitSet;
|
||||
BitSetPtr overrun = monitorElement->overrunBitSet;
|
||||
String buffer;
|
||||
changed->toString(&buffer);
|
||||
out << " changed " << buffer;
|
||||
buffer.clear();
|
||||
overrun->toString(&buffer);
|
||||
out << " overrun " << buffer;
|
||||
double elementsPerSec = nElements;
|
||||
elementsPerSec /= diff;
|
||||
if(elementsPerSec>10.0e9) {
|
||||
elementsPerSec /= 1e9;
|
||||
out << " gigaElements/sec " << elementsPerSec;
|
||||
} else if(elementsPerSec>10.0e6) {
|
||||
elementsPerSec /= 1e6;
|
||||
out << " megaElements/sec " << elementsPerSec;
|
||||
} else if(elementsPerSec>10.0e3) {
|
||||
elementsPerSec /= 1e3;
|
||||
out << " kiloElements/sec " << elementsPerSec;
|
||||
} else {
|
||||
out << " Elements/sec " << elementsPerSec;
|
||||
}
|
||||
cout << out.str() << endl;
|
||||
timeStampLast = timeStamp;
|
||||
nSinceLastReport = 0;
|
||||
nElements = 0;
|
||||
}
|
||||
++nSinceLastReport;
|
||||
} else {
|
||||
cout << "size = 0" << endl;
|
||||
}
|
||||
|
374
example/src/arrayPerformance/longArrayPut.cpp
Normal file
374
example/src/arrayPerformance/longArrayPut.cpp
Normal file
@ -0,0 +1,374 @@
|
||||
/* longArrayPut.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.08.09
|
||||
*/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/longArrayPut.h>
|
||||
#include <pv/caProvider.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::ostringstream;
|
||||
|
||||
static String requesterName("longArrayPut");
|
||||
static String request("value");
|
||||
static epics::pvData::Mutex printMutex;
|
||||
|
||||
class LongArrayChannelPut :
|
||||
virtual public ChannelRequester,
|
||||
virtual public ChannelPutRequester,
|
||||
public std::tr1::enable_shared_from_this<LongArrayChannelPut>,
|
||||
public epicsThreadRunable
|
||||
{
|
||||
public:
|
||||
LongArrayChannelPut(
|
||||
String providerName,
|
||||
String channelName,
|
||||
size_t arraySize,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelPut,
|
||||
double delayTime)
|
||||
: providerName(providerName),
|
||||
channelName(channelName),
|
||||
arraySize(arraySize),
|
||||
iterBetweenCreateChannel(iterBetweenCreateChannel),
|
||||
iterBetweenCreateChannelPut(iterBetweenCreateChannelPut),
|
||||
delayTime(delayTime),
|
||||
isDestroyed(false),
|
||||
runReturned(false),
|
||||
threadName("longArrayPut")
|
||||
{}
|
||||
virtual ~LongArrayChannelPut(){}
|
||||
bool init();
|
||||
virtual void destroy();
|
||||
virtual void run();
|
||||
virtual String getRequesterName() { return requesterName;}
|
||||
virtual void message(String const & message, MessageType messageType)
|
||||
{
|
||||
Lock guard(printMutex);
|
||||
cout << requesterName << " message " << message << endl;
|
||||
}
|
||||
virtual void channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel);
|
||||
virtual void channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState);
|
||||
virtual void channelPutConnect(
|
||||
Status const & status,
|
||||
ChannelPut::shared_pointer const & channelPut,
|
||||
PVStructurePtr const &pvStructure,
|
||||
BitSetPtr const &bitSet);
|
||||
virtual void putDone(Status const & status);
|
||||
virtual void getDone(Status const & status){}
|
||||
private:
|
||||
LongArrayChannelPutPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
String providerName;
|
||||
String channelName;
|
||||
size_t arraySize;
|
||||
int iterBetweenCreateChannel;
|
||||
int iterBetweenCreateChannelPut;
|
||||
double delayTime;
|
||||
bool isDestroyed;
|
||||
bool runReturned;
|
||||
epics::pvData::String threadName;
|
||||
Status status;
|
||||
Event event;
|
||||
Mutex mutex;
|
||||
std::auto_ptr<epicsThread> thread;
|
||||
Channel::shared_pointer channel;
|
||||
ChannelPut::shared_pointer channelPut;
|
||||
PVStructurePtr pvStructure;
|
||||
PVLongArrayPtr pvLongArray;
|
||||
BitSetPtr bitSet;
|
||||
};
|
||||
|
||||
bool LongArrayChannelPut::init()
|
||||
{
|
||||
ChannelProvider::shared_pointer channelProvider = getChannelAccess()->getProvider(providerName);
|
||||
if(channelProvider==NULL) {
|
||||
cout << "provider " << providerName << " not found" << endl;
|
||||
return false;
|
||||
}
|
||||
channel = channelProvider->createChannel(channelName,getPtrSelf(),0);
|
||||
event.wait();
|
||||
if(!status.isOK()) return false;
|
||||
CreateRequest::shared_pointer createRequest = CreateRequest::create();
|
||||
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
||||
if(pvRequest==NULL) {
|
||||
cout << "request logic error " << createRequest->getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
channelPut = channel->createChannelPut(getPtrSelf(),pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) return false;
|
||||
thread = std::auto_ptr<epicsThread>(new epicsThread(
|
||||
*this,
|
||||
threadName.c_str(),
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
epicsThreadPriorityLow));
|
||||
thread->start();
|
||||
event.signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LongArrayChannelPut::destroy()
|
||||
{
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
event.signal();
|
||||
while(true) {
|
||||
if(runReturned) break;
|
||||
epicsThreadSleep(.01);
|
||||
}
|
||||
thread->exitWait();
|
||||
channel->destroy();
|
||||
channelPut.reset();
|
||||
channel.reset();
|
||||
}
|
||||
|
||||
void LongArrayChannelPut::channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel)
|
||||
{
|
||||
if(!status.isOK()) message(status.getMessage(),errorMessage);
|
||||
this->status = status;
|
||||
this->channel = channel;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void LongArrayChannelPut::channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState)
|
||||
{
|
||||
MessageType messageType =
|
||||
(connectionState==Channel::CONNECTED ? infoMessage : errorMessage);
|
||||
message("channelStateChange",messageType);
|
||||
}
|
||||
|
||||
|
||||
void LongArrayChannelPut::channelPutConnect(
|
||||
Status const & status,
|
||||
ChannelPut::shared_pointer const & channelPut,
|
||||
PVStructurePtr const &pvStructure,
|
||||
BitSetPtr const &bitSet)
|
||||
{
|
||||
this->status = status;
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
event.signal();
|
||||
return;
|
||||
}
|
||||
this->channelPut = channelPut;
|
||||
this->pvStructure = pvStructure;
|
||||
this->bitSet = bitSet;
|
||||
bool structureOK(true);
|
||||
PVFieldPtr pvField = pvStructure->getSubField("value");
|
||||
if(pvField==NULL) {
|
||||
structureOK = false;
|
||||
} else {
|
||||
FieldConstPtr field = pvField->getField();
|
||||
if(field->getType()!=scalarArray) {
|
||||
structureOK = false;
|
||||
} else {
|
||||
ScalarArrayConstPtr scalarArray = dynamic_pointer_cast<const ScalarArray>(field);
|
||||
if(scalarArray->getElementType()!=pvLong) structureOK = false;
|
||||
}
|
||||
}
|
||||
if(!structureOK) {
|
||||
String mess("channelPutConnect: illegal structure");
|
||||
message(mess,errorMessage);
|
||||
this->status = Status(Status::STATUSTYPE_ERROR,mess);
|
||||
}
|
||||
pvLongArray = static_pointer_cast<PVLongArray>(pvField);
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void LongArrayChannelPut::run()
|
||||
{
|
||||
while(true) {
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
TimeStamp timeStamp;
|
||||
TimeStamp timeStampLast;
|
||||
timeStampLast.getCurrent();
|
||||
int numChannelPut = 0;
|
||||
int numChannelCreate = 0;
|
||||
size_t nElements = 0;
|
||||
while(true) {
|
||||
nElements += sizeof(int64) * arraySize;
|
||||
shared_vector<int64> xxx(arraySize,numChannelPut);
|
||||
shared_vector<const int64> data(freeze(xxx));
|
||||
pvLongArray->replace(data);
|
||||
bitSet->set(pvLongArray->getFieldOffset());
|
||||
channelPut->put(false);
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
if(delayTime>0.0) epicsThreadSleep(delayTime);
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
timeStamp.getCurrent();
|
||||
double diff = TimeStamp::diff(timeStamp,timeStampLast);
|
||||
if(diff>=1.0) {
|
||||
ostringstream out;
|
||||
out << "put numChannelPut " << numChannelPut;
|
||||
out << " time " << diff ;
|
||||
double elementsPerSec = nElements;
|
||||
elementsPerSec /= diff;
|
||||
if(elementsPerSec>10.0e9) {
|
||||
elementsPerSec /= 1e9;
|
||||
out << " gigaElements/sec " << elementsPerSec;
|
||||
} else if(elementsPerSec>10.0e6) {
|
||||
elementsPerSec /= 1e6;
|
||||
out << " megaElements/sec " << elementsPerSec;
|
||||
} else if(elementsPerSec>10.0e3) {
|
||||
elementsPerSec /= 1e3;
|
||||
out << " kiloElements/sec " << elementsPerSec;
|
||||
} else {
|
||||
out << " Elements/sec " << elementsPerSec;
|
||||
}
|
||||
cout << out.str() << endl;
|
||||
timeStampLast = timeStamp;
|
||||
nElements = 0;
|
||||
}
|
||||
++numChannelCreate;
|
||||
bool createPut = false;
|
||||
if(iterBetweenCreateChannel!=0) {
|
||||
if(numChannelCreate>=iterBetweenCreateChannel) {
|
||||
channel->destroy();
|
||||
ChannelProvider::shared_pointer channelProvider =
|
||||
getChannelAccess()->getProvider(providerName);
|
||||
channel = channelProvider->createChannel(channelName,getPtrSelf(),0);
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
return;
|
||||
}
|
||||
cout<< "createChannel success" << endl;
|
||||
createPut = true;
|
||||
numChannelCreate = 0;
|
||||
numChannelPut = 0;
|
||||
}
|
||||
}
|
||||
++numChannelPut;
|
||||
if(iterBetweenCreateChannelPut!=0) {
|
||||
if(numChannelPut>=iterBetweenCreateChannelPut) createPut = true;
|
||||
}
|
||||
if(createPut) {
|
||||
numChannelPut = 0;
|
||||
channelPut->destroy();
|
||||
CreateRequest::shared_pointer createRequest = CreateRequest::create();
|
||||
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
||||
if(pvRequest==NULL) {
|
||||
cout << "request logic error " << createRequest->getMessage() << endl;
|
||||
return ;
|
||||
}
|
||||
channelPut = channel->createChannelPut(getPtrSelf(),pvRequest);
|
||||
event.wait();
|
||||
if(isDestroyed) {
|
||||
runReturned = true;
|
||||
return;
|
||||
}
|
||||
if(!status.isOK()) {
|
||||
message(status.getMessage(),errorMessage);
|
||||
return;
|
||||
}
|
||||
cout<< "createChannelPut success" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LongArrayChannelPut::putDone(Status const & status)
|
||||
{
|
||||
event.signal();
|
||||
}
|
||||
|
||||
|
||||
LongArrayPutPtr LongArrayPut::create(
|
||||
String const &providerName,
|
||||
String const & channelName,
|
||||
size_t arraySize,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelPut,
|
||||
double delayTime)
|
||||
{
|
||||
LongArrayPutPtr longArrayPut(
|
||||
new LongArrayPut(
|
||||
providerName,
|
||||
channelName,
|
||||
arraySize,
|
||||
iterBetweenCreateChannel,
|
||||
iterBetweenCreateChannelPut,
|
||||
delayTime));
|
||||
if(!longArrayPut->init()) longArrayPut.reset();
|
||||
return longArrayPut;
|
||||
}
|
||||
|
||||
LongArrayPut::LongArrayPut(
|
||||
String const &providerName,
|
||||
String const & channelName,
|
||||
size_t arraySize,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelPut,
|
||||
double delayTime)
|
||||
: providerName(providerName),
|
||||
channelName(channelName),
|
||||
arraySize(arraySize),
|
||||
iterBetweenCreateChannel(iterBetweenCreateChannel),
|
||||
iterBetweenCreateChannelPut(iterBetweenCreateChannelPut),
|
||||
delayTime(delayTime)
|
||||
{}
|
||||
|
||||
|
||||
LongArrayPut::~LongArrayPut() {}
|
||||
|
||||
bool LongArrayPut::init()
|
||||
{
|
||||
longArrayChannelPut = LongArrayChannelPutPtr(new LongArrayChannelPut(
|
||||
providerName,
|
||||
channelName,
|
||||
arraySize,
|
||||
iterBetweenCreateChannel,
|
||||
iterBetweenCreateChannelPut,
|
||||
delayTime));
|
||||
return longArrayChannelPut->init();
|
||||
}
|
||||
|
||||
void LongArrayPut::destroy()
|
||||
{
|
||||
longArrayChannelPut->destroy();
|
||||
longArrayChannelPut.reset();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
71
example/src/arrayPerformance/longArrayPut.h
Normal file
71
example/src/arrayPerformance/longArrayPut.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* longArrayPut.h */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.08.09
|
||||
*/
|
||||
#ifndef LONGARRAYPUT_H
|
||||
#define LONGARRAYPUT_H
|
||||
|
||||
#include <pv/event.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/pvAccess.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class LongArrayPut;
|
||||
typedef std::tr1::shared_ptr<LongArrayPut> LongArrayPutPtr;
|
||||
|
||||
|
||||
class LongArrayChannelPut;
|
||||
typedef std::tr1::shared_ptr<LongArrayChannelPut> LongArrayChannelPutPtr;
|
||||
|
||||
class LongArrayPut :
|
||||
public std::tr1::enable_shared_from_this<LongArrayPut>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(LongArrayPut);
|
||||
static LongArrayPutPtr create(
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName,
|
||||
size_t arraySize = 100,
|
||||
int iterBetweenCreateChannel = 0,
|
||||
int iterBetweenCreateChannelPut = 0,
|
||||
double delayTime = 0.0);
|
||||
~LongArrayPut();
|
||||
void destroy();
|
||||
private:
|
||||
LongArrayPutPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
LongArrayPut(
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName,
|
||||
size_t arraySize,
|
||||
int iterBetweenCreateChannel,
|
||||
int iterBetweenCreateChannelPut,
|
||||
double delayTime);
|
||||
bool init();
|
||||
|
||||
epics::pvData::String providerName;
|
||||
epics::pvData::String channelName;
|
||||
size_t arraySize;
|
||||
int iterBetweenCreateChannel;
|
||||
int iterBetweenCreateChannelPut;
|
||||
double delayTime;
|
||||
LongArrayChannelPutPtr longArrayChannelPut;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* LONGARRAYPUT_H */
|
@ -54,7 +54,7 @@ class ElementQueue :
|
||||
public:
|
||||
POINTER_DEFINITIONS(ElementQueue);
|
||||
virtual ~ElementQueue(){}
|
||||
virtual bool dataChanged(bool firstMonitor) = 0;
|
||||
virtual bool dataChanged() = 0;
|
||||
protected:
|
||||
ElementQueuePtr getPtrSelf()
|
||||
{
|
||||
@ -79,7 +79,7 @@ public:
|
||||
virtual void destroy(){}
|
||||
virtual Status start();
|
||||
virtual Status stop();
|
||||
virtual bool dataChanged(bool firstMonitor);
|
||||
virtual bool dataChanged();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void release(MonitorElementPtr const &monitorElement);
|
||||
private:
|
||||
@ -168,15 +168,13 @@ void MonitorLocal::destroy()
|
||||
|
||||
Status MonitorLocal::start()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "MonitorLocal::start() " << endl;
|
||||
}
|
||||
if(isDestroyed) return wasDestroyedStatus;
|
||||
firstMonitor = true;
|
||||
cout << "MonitorLocal::start() " << endl;
|
||||
}
|
||||
if(isDestroyed) return wasDestroyedStatus;
|
||||
firstMonitor = true;
|
||||
return queue->start();
|
||||
}
|
||||
|
||||
@ -229,7 +227,7 @@ void MonitorLocal::dataChanged()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) return;
|
||||
getMonitorEvent = queue->dataChanged(firstMonitor);
|
||||
getMonitorEvent = queue->dataChanged();
|
||||
firstMonitor = false;
|
||||
}
|
||||
if(getMonitorEvent) monitorRequester->monitorEvent(getPtrSelf());
|
||||
@ -401,7 +399,7 @@ Status MultipleElementQueue::stop()
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
bool MultipleElementQueue::dataChanged(bool firstMonitor)
|
||||
bool MultipleElementQueue::dataChanged()
|
||||
{
|
||||
MonitorLocalPtr ml = monitorLocal.lock();
|
||||
if(ml==NULL) return false;
|
||||
@ -423,7 +421,6 @@ bool MultipleElementQueue::dataChanged(bool firstMonitor)
|
||||
queueIsFull = true;
|
||||
latestMonitorElement = monitorElement;
|
||||
}
|
||||
if(firstMonitor) changedBitSet->set(0);
|
||||
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
|
||||
ml->getPVCopy()->updateCopyFromBitSet(
|
||||
pvStructure,changedBitSet);
|
||||
|
Reference in New Issue
Block a user