main addition is array performance example

This commit is contained in:
Marty Kraimer
2013-08-28 10:51:04 -04:00
parent 614491c02e
commit 64afb395a8
38 changed files with 3277 additions and 982 deletions
+189 -47
View File
@@ -38,23 +38,18 @@
<h1>pvDatabaseCPP</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 06-Aug-2013</h2>
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 28-Aug-2013</h2>
<dl>
<dt>Latest version:</dt>
<dd><a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
</dd>
<dt>This version:</dt>
<dd><a
href=
"http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130806.html">
pvDatabaseCPP20130806.html</a>
href= "pvDatabaseCPP_20130828.html">pvDatabaseCPP20130828.html</a>
</dd>
<dt>Previous version:</dt>
<dd><a
href=
"http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130725.html">
pvDatabaseCPP20130725.html</a>
<dd><a href="pvDatabaseCPP_20130725.html">pvDatabaseCPP20130725.html</a>
</dd>
<dt>Editors:</dt>
<dd>Marty Kraimer, BNL</dd>
@@ -78,33 +73,44 @@ The minimum that an extenson must provide is a top level PVStructure and a proce
<h2 class="nocount">Status of this Document</h2>
<p>This is the 06-Aug-2013 version of the definition of pvDatabaseCPP.
<p>This is the 28-Aug-2013 version of of pvDatabaseCPP.
<p><b>NOTE:</b>
This is built against pvDataCPP-md NOT against pvDataCPP.
To build you must also
checkout pvAccessCPP and build it against pvDataCPP-md.
</p>
</p>
<p>All channel methods except channelRPCi, which is implemented
<p>All channel methods except channelRPC, which is implemented
by pvAccess, have been implemented.
This project is ready for alpha users.
</p>
<p>Future enhancements in priority order:</p>
<dl>
<dt>Termination issues.</dt>
<dd>There are memory leak and other issues when either the main programs or v3IOC terminates.</dd>
<dt>Array performance</dt>
<dd>Create an example record that continuously creates array data.
The idea is to compare performance allocating memory from the
heap vs using a free list.</dd>
<dt>Separate example that also has pvaSrv</dt>
<dd>Create a separate example that combines a V3IOC,
a pvDatabase, and pvaSrv.</dd>
a pvDatabase, and pvaSrv.
This will not be done until pvDataCPP-md is merged into pvDataCPP.
</dd>
<dt>channelArray</dt>
<dd>The arguments that have type <b>int</b> should be changed to <b>size_t</b>
This will not be done until pvDataCPP-md is merged into pvDataCPP.
</dd>
<dt>arrayPerformanceMain</dt>
<dd>When this is run without a pvAccess client the performance is great.
But when a pvAccess client is monitoring then the preformance slows
more then expected.
I do not understand and must spend more time determining why.</dd>
<dt>Monitor Algorithms</dt>
<dd>Monitor algorithms have not been implemented.
Thus all monitors are onPut.</dd>
<dt>Testing</dt>
<dd>Needs more testing</dd>
<dd>Needs more testing.
Also none of the examples that use pvAccess can be run with gdb.
</dd>
<dt>Termination issues.</dt>
<dd>longArrayMonitor has memory leaks when main terminates.</dt>
<dt>Create regression tests</dt>
<dd>Currently only examples exist and have been used for testing.</dd>
</dl>
<div id="toc">
@@ -228,7 +234,7 @@ try starting exampleServerMain and exampleServer.
<p>This example provides the exampleCounter record in addition to a number of other PVRecords.
Like exampleCounter it can be started either as a standalone main program or as
a part of a V3IOC.
The exampleServer pvDatabase includes the following records:</p>
The exampleServer pvDatabase has many records including the following:</p>
<dl>
<dt>exampleCounter</dt>
<dd>A record that is an instance of exampleCounter described below.
@@ -245,7 +251,7 @@ The exampleServer pvDatabase includes the following records:</p>
<dd>Can be used by channelGet, channelPut, channelPutGet, and monitor.</dd>
<dt>laptoprecordListPGRPC</dt>
<dd>Implements the record expected by swtshell channelList.
It can also be used via channelPutGet but unnecessary.</dd>
It can also be used via channelPutGet.</dd>
<dt>traceRecordPGRPC</dt>
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
</dl>
@@ -253,14 +259,14 @@ The exampleServer pvDatabase includes the following records:</p>
<h3>swtshell</h3>
<p>The Java program
<a
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
href="http://epics-pvdata.sourceforge.net/docbuild/swtshellJava/tip/documentation/swtshellJava.html">
swtshell</a>
can be used to access pvDatabase.</p>
<p>In particular read the sections "Getting Started" and "Simple Example".
They will work on the exampleServer with the following differences:
<dl>
<dt>startExample.zip</dt>
<dd>Do NOT use this. Instead run exampleServer</dd>
<dd>Do NOT use this. Instead run the exampleServer as described above.</dd>
<dt>channelList result</dt>
<dd>The result of channelList will show the list of records that
exampleServer has rather than the records from startExample.zip</dd>
@@ -270,7 +276,7 @@ They will work on the exampleServer with the following differences:
<h3>Relationship with pvIOCJava.</h3>
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
which also implements a pvDatabase.
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
PVDatabaseCPP implements the core components required to create a network accessible database of smart
memory resident records.
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
provides.
@@ -308,11 +314,11 @@ mrk&gt; bin/linux-x86_64/exampleCounter
by a pvAccess client.
It is located in directory pvDatabaseCPP/example/exampleCounter.
</dd>
<dt>v3IOC/exampleCounter</dt>
<dt>V3IOC/exampleCounter</dt>
<dd>This is a directory that packages exampleCounter to make it
part of a v3IOC.</dd>
part of a V3IOC.</dd>
<dt>iocBoot/exampleCounter</dt>
<dd>A place to start exampleCounter as part of a v3IOC.
<dd>A place to start exampleCounter as part of a V3IOC.
It follows the normal iocCore conventions.</dd>
</dl>
<h4>ExampleCounter.h</h4>
@@ -425,7 +431,7 @@ bool ExampleCounter::init()
initPVRecord();
epics::pvData::PVFieldPtr pvField;
pvValue = getPVStructure()-&gt;getLongField("value");
if(pvValue.get()==NULL) return false;
if(pvValue==NULL) return false;
return true;
}
</pre>
@@ -487,19 +493,19 @@ This:
<li>Prints exampleCounter on standard out.</li>
<li>Runs forever until the user types exit on standard in.</li>
</ul>
<h4>v3IOC exampleCounter</h4>
<h4>V3IOC exampleCounter</h4>
<p>This has two subdirectories:
<dl>
<dt>Db</dt>
<dd>This has a template for a single v3Record.</dd>
<dt>src</dt>
<dd>This has code to allow exampleCounter to reside in a v3IOC.</dd>
<dd>This has code to allow exampleCounter to reside in a V3IOC.</dd>
</dl>
</p>
<p>The src directory has the following components:</p>
<dl>
<dt>exampleCounterMain.cpp</dt>
<dd>This is just a standard Main for a v3IOC.</dd>
<dd>This is just a standard Main for a V3IOC.</dd>
<dt>exampleCounterInclude.dbd</dt>
<dd>This is:
<pre>
@@ -514,7 +520,7 @@ registrar("exampleCounterRegister")
</dd>
<dt>exampleCounter.cpp</dt>
<dd>This is the code that registers a command the can be issued
via the iocsh, which is the console for a v3IOC.
via the iocsh, which is the console for a V3IOC.
The example supports a single command:
<pre>
exampleCounterCreateRecord recordName
@@ -561,9 +567,9 @@ The rest of this document discusses only the first phase.</p>
<dt>PVRecord and PVDatabase</dt>
<dd>Defined below.</dd>
<dt>The localChannelProvider itself</dt>
<dd>This is the pvAccess package in pvIOCJava.
The localChannelProvider will access data from PVRecords.
It will implement all channel methods.</dd>
<dd>This is the C++ implementation of package pvAccess in pvIOCJava.
The localChannelProvider accesses data from PVRecords.
It implements all channel methods except channelRPC, which is implemented by pvAccessCPP.</dd>
</dl>
<h3>Minumum Features Required for pvRecord</h3>
<p>The first phase will only implement record processing, i. e.
@@ -590,7 +596,7 @@ The following are the minimium features required</p>
<p>The following sections describes the classes required for the first phase.</p>
<h2>iocshell commands</h2>
<p>The following iocsh commands are provided:</p>
<p>The following iocsh commands are provided for a V3IOC:</p>
<dl>
<dt>startPVAClient</dt>
<dd>Starts the client side of pvAccess.s
@@ -608,15 +614,16 @@ The following are the minimium features required</p>
<dd>Provides a list of all the pvRecords in database <b>master</b>
It is similar to the iocsh command <b>dbl</b></dd>
</dl>
<p>The client commands are provided via PVAClientRegister.dbd and the othet commands
<p>The client commands are provided via PVAClientRegister.dbd and the other commands
via PVAServerRegister.dbd.</p>
<p>In addition any code that implements a PVRecord must implement an ioc command.
The directory example has examples of how to implement the registration code.
See example/v3IOC/exampleCounter/src/ for a simple example.</p>
See example/V3IOC/exampleCounter/src/ for a simple example.</p>
<h2>database</h2>
<p>This directory has the following files:</p>
<h3>src/database</h3>
<p>This Directory has the following files:</p>
<dl>
<dt>pvDatabase.h</dt>
<dd>
@@ -634,10 +641,10 @@ See example/v3IOC/exampleCounter/src/ for a simple example.</p>
This can be used to create a "dumb" record where all changes are
done by clients.
</dd>
<dt>exampleCounter.h</dt>
<dd>
This was described in the introduction.
</dd>
</dl>
<h3>src/special</h3>
<p>This directory has the following files:</p>
<dl>
<dt>powerSupplyRecordTest.h</dt>
<dd>
This provides code that simulates a power supply.
@@ -663,6 +670,7 @@ result = master-&gt;addRecord(pvRecord);
another record. See below for a discussion of trace level.</dd>
</dl>
<h3>pvDatabase.h</h3>
<p>The classes in pvDatabase.h describe a database of memory resident
smart records.
It describes the following classes:</p>
@@ -1121,7 +1129,7 @@ The only algorithm currently implemented is <b>onPut</b>
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
as seen by a client.
See
<a href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
For details.</p>
<p>
monitorFactory implements the
@@ -1324,7 +1332,7 @@ i. e. copy on write semantics are enforced. This is done automatically
by pvData and not by pvDatabase.</p>
<h4>Some details</h4>
<p>As mentioned before a pvDatabase server can be either a separate process,
i. e. a main program, or can be part of a v3IOC.</p>
i. e. a main program, or can be part of a V3IOC.</p>
<p>A main pvDatabase server issues the following calls:</p>
<pre>
ClientFactory::start();
@@ -1363,7 +1371,7 @@ examplePVADoubleArrayGet shows how to use pvAccess to get data.</p>
<dd>This is the implementation code for the example.</dd>
<dt>example/examplePVADoubleArrayGet</dt>
<dd>This is the code that starts the example as a main program.</dd>
<dt>example/v3IOC/examplePVADoubleArrayGet/src</dt>
<dt>example/V3IOC/examplePVADoubleArrayGet/src</dt>
<dd>This is the code for starting the example as part of a V3IOC.</dd>
<dt>iocBoot/examplePVADoubleArrayGet</dt>
<dd>This has the st.cmd files to start the example.</dd>
@@ -1557,7 +1565,7 @@ This is the record that can be accessed via pvAccess if the channelName is
<p>It the runs forever until the exit is typed.</p>
<h4>Start the example as part of a V3IOC</h4>
The directory example/v3IOC/examplePVADoubleArrayGet has two subdirectories: Db and src.
The directory example/V3IOC/examplePVADoubleArrayGet has two subdirectories: Db and src.
These are like for any other V3IOC application.
The Db directory is for a regular ai record.
The src directory has code similar to any V3IOC application.
@@ -1579,6 +1587,140 @@ 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>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/arrayPerformanceMain -help
arrayPerformanceMain recordName size delay providerName nMonitor useQueue
default
arrayPerformance arrayPerformance 50000000 0.001 local 1 false
mrk&gt; bin/linux-x86_64/longArrayMonitorMain -help
longArrayMonitorMain channelName useQueue
default
longArrayMonitorMain arrayPerformance false
mrk&gt;
</pre>
<h3>Example output</h3>
<pre>
mrk&gt; bin/linux-x86_64/arrayPerformanceMain
arrayPerformance arrayPerformance 50000000 0.01 local 1 false
...
first 0 last 0 sum 0 elements/sec 525.011million changed {1, 2} overrun {}
first 1 last 1 sum 50000000 elements/sec 494.511million changed {1, 2} overrun {}
first 2 last 2 sum 100000000 elements/sec 515.34million changed {1, 2} overrun {}
first 3 last 3 sum 150000000 elements/sec 154.402million changed {1, 2} overrun {}
first 4 last 4 sum 200000000 elements/sec 513.414million changed {1, 2} overrun {}
first 5 last 5 sum 250000000 elements/sec 473.672million changed {1, 2} overrun {}
first 6 last 6 sum 300000000 elements/sec 503.855million changed {1, 2} overrun {}
arrayPerformance value 8 time 1.66373 iterations/sec 4.80847 elements/sec 240.424million
...
</pre>
<h3>arrayPerformance</h3>
<p>
This creates a PVRecord that has the structure:.
<pre>
recordName
long[] value
timeStamp timeStamp
alarm alarm
</pre>
Thus it holds an array of 64 bit integers.</p>
<p>The record has support that consists of a separate thread that runs
until the record is destroyed executing the following algorithm:</p>
<dl>
<dt>report</dt>
<dd>At least once a second it produces a report.
In the above example output each line starting with
<b>ArrayPerformance</b> is an arrayPerformance report.
</dd>
<dt>create array</dt>
<dd>A new shared_vector is created and each element is set equal
to the interation count.</dd>
<dt>lock</dt>
<dd>The arrayPerformance record is locked.</dd>
<dt>Begin group put</dt>
<dd>beginGroupReport is called.</dd>
<dt>replace</dt>
<dd>The value field of the record is replaced
with the newly created shared_vector.</dd>
<dt>process</dt>
<dd>The record is then processed. This causes the timeStamp to
be set to the current time.</dd>
<dt>End group put</dt>
<dd>endGroupPut is called.</dd>
<dt>unlock</dt>
<dd>The arrayPerformance record is unlocked.</dd>
<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>useQueue</dt>
<dd>Should the longArrayMonitors use a queue?
This must be <b>true</b> or <b>false</b>.
</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>
<p>The arguments for longArrayMonitorMain are:</p>
<dl>
<dt>channelName</dt>
<dt>useQueue</dt>
</dl>
<h3>Some results</h3>
<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>
<p>When test are performed with large arrays it is a good idea to also
run a system monitor facility and check memory and swap history.
If a test configuration causes physical memory to be exhausted
then performance becomes <b>very</b> poor.
You do not want to do this.</p>
<h4>arrayPerformance results</h4>
<p>The simplest test to run arrayPerformance with the defaults:</p>
<pre>
mrk&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/arrayPerformanceMain
</pre>
<p>This means that the array will hold 50 million elements.
The delay will be a millisecond.
There will be a single monitor and it will connect directly
to the local channelProvider, i. e. it will not use any network
connection.</p>
<p>The report shows that arrayPerformance can perform about 8 iterations per second
and is putting about 350million elements per second.
Since each element is an int64 this means about 2.8gigaBytes per second.
</p>
<p>When no monitors are requested and a remote longArrayMonitorMain is run:<p>
<pre>
mr&gt; pwd
/home/hg/pvDatabaseCPP-md
mrk&gt; bin/linux-x86_64/longArrayMonitorMain
</pre>
<p>The performance drops to about 90million elements per second.
In addition the time between reports varies from just over 1 second to 3 seconds.
I do not understand why.</p>
</div>
</body>