Merged Michael's dbConvert-memmove branch.

This commit is contained in:
Andrew Johnson
2014-06-13 15:42:36 -05:00
6 changed files with 355 additions and 180 deletions

View File

@@ -38,6 +38,29 @@
#include "recGbl.h"
#include "dbConvert.h"
/* Helper for copy as bytes with no type conversion.
* Assumes nRequest <= no_bytes
* nRequest, no_bytes, and offset should be given in bytes.
*/
static void copyNoConvert(const void *pfrom,
void *pto,
long nRequest,
long no_bytes,
long offset)
{
if(offset>0 && offset < no_bytes && offset+nRequest > no_bytes) {
const size_t N = no_bytes - offset;
/* copy with wrap */
memmove(pto, pfrom + offset, N);
memmove(pto + N, pfrom, nRequest - N);
} else {
/* no wrap, just copy */
memmove(pto, pfrom + offset, nRequest);
}
}
#define COPYNOCONVERT(N, FROM, TO, NREQ, NO_ELEM, OFFSET) \
copyNoConvert(FROM, TO, (N)*(NREQ), (N)*(NO_ELEM), (N)*(OFFSET))
/* DATABASE ACCESS GET CONVERSION SUPPORT */
static long getStringString (
@@ -427,12 +450,7 @@ static long getCharChar(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(char), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -454,12 +472,7 @@ static long getCharUchar(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(char), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -638,12 +651,7 @@ static long getUcharChar(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(unsigned char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned char), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -658,12 +666,7 @@ static long getUcharUchar(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(unsigned char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned char), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -870,6 +873,7 @@ static long getShortUchar(
}
return(0);
}
static long getShortShort(
const dbAddr *paddr,
void *pto, long nRequest, long no_elements, long offset)
@@ -881,12 +885,7 @@ static long getShortShort(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(short), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -901,12 +900,7 @@ static long getShortUshort(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(short), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1084,12 +1078,7 @@ static long getUshortShort(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(unsigned short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned short), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1104,12 +1093,7 @@ static long getUshortUshort(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(unsigned short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned short), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1328,12 +1312,7 @@ static long getLongLong(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(epicsInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(long), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1348,12 +1327,7 @@ static long getLongUlong(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(epicsInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(long), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1532,12 +1506,7 @@ static long getUlongLong(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(epicsUInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned long), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1552,12 +1521,7 @@ static long getUlongUlong(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(epicsUInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned long), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -1782,12 +1746,7 @@ static long getFloatFloat(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(float *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(float), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -2013,12 +1972,7 @@ static long getDoubleDouble(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(double *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(double), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -2228,12 +2182,7 @@ static long getEnumEnum(
*pbuffer = *psrc;
return(0);
}
psrc += offset;
while (nRequest) {
*pbuffer++ = *psrc++;
if(++offset==no_elements) psrc=(epicsEnum16 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(epicsEnum16), paddr->pfield, pto, nRequest, no_elements, offset);
return(0);
}
@@ -2734,12 +2683,7 @@ static long putCharChar(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(char), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -2754,12 +2698,7 @@ static long putCharUchar(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(unsigned char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned char), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -2940,12 +2879,7 @@ static long putUcharChar(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned char), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -2960,12 +2894,7 @@ static long putUcharUchar(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(unsigned char *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned char), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3186,12 +3115,7 @@ static long putShortShort(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(short), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3206,12 +3130,7 @@ static long putShortUshort(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(unsigned short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(short), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3392,12 +3311,7 @@ static long putUshortShort(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned short), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3412,12 +3326,7 @@ static long putUshortUshort(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(unsigned short *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(unsigned short), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3638,12 +3547,7 @@ static long putLongLong(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(epicsInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(epicsInt32), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3658,12 +3562,7 @@ static long putLongUlong(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(epicsUInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(epicsInt32), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3844,12 +3743,7 @@ static long putUlongLong(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(epicsInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(epicsUInt32), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -3864,12 +3758,7 @@ static long putUlongUlong(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(epicsUInt32 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(epicsUInt32), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -4095,12 +3984,7 @@ static long putFloatFloat(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(float *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(float), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -4327,12 +4211,7 @@ static long putDoubleDouble(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(double *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(double), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}
@@ -4553,12 +4432,7 @@ static long putEnumEnum(
*pdest = *pbuffer;
return(0);
}
pdest += offset;
while (nRequest) {
*pdest++ = *pbuffer++;
if(++offset==no_elements) pdest=(epicsEnum16 *)paddr->pfield;
nRequest--;
}
COPYNOCONVERT(sizeof(epicsEnum16), pfrom, paddr->pfield, nRequest, no_elements, offset);
return(0);
}

View File

@@ -12,6 +12,7 @@
#define INCdbConverth
#include "dbFldTypes.h"
#include "dbAddr.h"
#include "shareLib.h"
#ifdef __cplusplus

View File

@@ -16,6 +16,11 @@ xRec_SRCS = xRecord.c
PROD_LIBS = xRec dbCore ca Com
TESTPROD_HOST += testdbConvert
testdbConvert_SRCS += testdbConvert.c
testHarness_SRCS += testdbConvert.c
TESTS += testdbConvert
TESTPROD_HOST += callbackTest
callbackTest_SRCS += callbackTest.c
testHarness_SRCS += callbackTest.c
@@ -56,6 +61,9 @@ testHarness_SRCS += arrShorthandTest_registerRecordDeviceDriver.cpp
TESTFILES += $(COMMON_DIR)/arrShorthandTest.dbd
TESTS += arrShorthandTest
TESTPROD_HOST += benchdbConvert
benchdbConvert_SRCS += benchdbConvert.c
# The testHarness runs all the test programs in a known working order.
testHarness_SRCS += epicsRunDbTests.c

View File

@@ -0,0 +1,124 @@
/*************************************************************************\
* Copyright (c) 2013 Brookhaven Science Assoc, as Operator of Brookhaven
* National Laboratory.
\*************************************************************************/
#include "string.h"
#include "cantProceed.h"
#include "dbAddr.h"
#include "dbConvert.h"
#include "dbDefs.h"
#include "epicsTime.h"
#include "epicsMath.h"
#include "epicsAssert.h"
#include "epicsUnitTest.h"
#include "testMain.h"
typedef struct {
size_t nelem, niter;
short *output;
short *input;
GETCONVERTFUNC getter;
DBADDR addr;
} testData;
static long runRep(testData *D)
{
size_t i;
for(i=0; i<D->niter; i++) {
D->getter(&D->addr, D->output, D->nelem, D->nelem, 0);
}
return 0;
}
static void runBench(size_t nelem, size_t niter, size_t nrep)
{
size_t i;
testData tdat;
double *reptimes;
testDiag("Using %lu element arrays.",(unsigned long)nelem);
testDiag("run %lu reps with %lu iterations each",
(unsigned long)nrep, (unsigned long)niter);
reptimes = callocMustSucceed(nrep, sizeof(*reptimes), "runBench");
tdat.output = callocMustSucceed(nelem, sizeof(*tdat.output), "runBench");
tdat.input = callocMustSucceed(nelem, sizeof(*tdat.input), "runBench");
tdat.nelem = nelem;
tdat.niter = niter;
tdat.getter = dbGetConvertRoutine[DBF_SHORT][DBF_SHORT];
memset(&tdat.addr, 0, sizeof(tdat.addr));
tdat.addr.field_type = DBF_SHORT;
tdat.addr.field_size = nelem*sizeof(*tdat.input);
tdat.addr.no_elements = nelem;
tdat.addr.pfield = (void*)tdat.input;
for(i=0; i<nelem; i++)
tdat.input[i] = (short)i;
for(i=0; i<nrep; i++)
{
epicsTimeStamp start, stop;
if(epicsTimeGetCurrent(&start)!=epicsTimeOK) {
testAbort("Failed to get timestamp");
goto done;
}
if(runRep(&tdat))
goto done;
if(epicsTimeGetCurrent(&stop)!=epicsTimeOK) {
testAbort("Failed to get timestamp");
goto done;
}
reptimes[i] = epicsTimeDiffInSeconds(&stop, &start);
testDiag("%lu bytes in %.03f ms. %.1f MB/s",
(unsigned long)(nelem*niter),
reptimes[i]*1e3,
(nelem*niter)/reptimes[i]/1e6);
}
{
double sum=0, sum2=0, mean;
for(i=0; i<nrep; i++) {
sum += reptimes[i];
sum2 += reptimes[i]*reptimes[i];
}
mean = sum/nrep;
testDiag("Final: %.04f ms +- %.05f ms. %.1f MB/s (for %lu elements)",
mean*1e3,
sqrt(sum2/nrep - mean*mean)*1e3,
(nelem*niter)/mean/1e6,
(unsigned long)nelem);
}
done:
free(reptimes);
free(tdat.input);
free(tdat.output);
}
MAIN(benchdbConvert)
{
testPlan(0);
runBench(1, 10000000, 10);
runBench(2, 5000000, 10);
runBench(10, 1000000, 10);
runBench(100, 100000, 10);
runBench(10000, 1000, 10);
runBench(100000, 100, 10);
runBench(1000000, 10, 10);
runBench(10000000, 1, 10);
return testDone();
}

View File

@@ -16,6 +16,7 @@
#include "epicsExit.h"
#include "dbmf.h"
int testdbConvert(void);
int callbackTest(void);
int dbStateTest(void);
int testDbChannel(void);
@@ -26,6 +27,7 @@ void epicsRunDbTests(void)
{
testHarness();
runTest(testdbConvert);
runTest(callbackTest);
runTest(dbStateTest);
runTest(testDbChannel);

View File

@@ -0,0 +1,166 @@
/*************************************************************************\
* Copyright (c) 2013 Brookhaven Science Assoc, as Operator of Brookhaven
* National Laboratory.
\*************************************************************************/
#include "string.h"
#include "cantProceed.h"
#include "dbConvert.h"
#include "dbDefs.h"
#include "epicsAssert.h"
#include "epicsUnitTest.h"
#include "testMain.h"
static const short s_input[] = {-1,0,1,2,3,4,5};
static const size_t s_input_len = NELEMENTS(s_input);
static void testBasicGet(void)
{
short *scratch;
DBADDR addr;
GETCONVERTFUNC getter;
getter = dbGetConvertRoutine[DBF_SHORT][DBF_SHORT];
scratch = callocMustSucceed(s_input_len, sizeof(s_input), "testBasicGet");
memset(&addr, 0, sizeof(addr));
addr.field_type = DBF_SHORT;
addr.field_size = s_input_len*sizeof(*scratch);
addr.no_elements = s_input_len;
addr.pfield = (void*)s_input;
testDiag("Test dbGetConvertRoutine[DBF_SHORT][DBF_SHORT]");
{
testDiag("Copy out first element");
getter(&addr, scratch, 1, s_input_len, 0);
testOk1(scratch[0]==s_input[0]);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Copy out entire array");
getter(&addr, scratch, s_input_len, s_input_len, 0);
testOk1(memcmp(scratch, s_input, sizeof(s_input))==0);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Copy out partial array");
getter(&addr, scratch, 2, s_input_len, 0);
testOk1(memcmp(scratch, s_input, sizeof(short)*2)==0);
testOk1(scratch[2]==0x4242);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Copy out w/ offset");
getter(&addr, scratch, 2, s_input_len, 1);
testOk1(memcmp(scratch, s_input+1, sizeof(short)*2)==0);
testOk1(scratch[2]==0x4242);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Copy out end of array");
getter(&addr, scratch, 2, s_input_len, s_input_len-2);
testOk1(s_input_len-2 == 5);
testOk1(memcmp(scratch, s_input+5, sizeof(short)*2)==0);
testOk1(scratch[2]==0x4242);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Copy out with wrap");
getter(&addr, scratch, 2, s_input_len, s_input_len-1);
testOk1(s_input_len-2 == 5);
testOk1(scratch[0] == s_input[6]);
testOk1(scratch[1] == s_input[0]);
testOk1(scratch[2]==0x4242);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Crazy copy from out of bounds offset");
addr.pfield = (short*)(2*sizeof(short));
getter(&addr, scratch, s_input_len, s_input_len, (long)(s_input-2)/sizeof(short));
testOk1(memcmp(scratch, s_input, sizeof(s_input))==0);
memset(scratch, 0x42, sizeof(s_input));
}
free(scratch);
}
static void testBasicPut(void)
{
short *scratch;
DBADDR addr;
PUTCONVERTFUNC putter;
putter = dbPutConvertRoutine[DBF_SHORT][DBF_SHORT];
scratch = callocMustSucceed(s_input_len, sizeof(s_input), "testBasicPut");
memset(&addr, 0, sizeof(addr));
addr.field_type = DBF_SHORT;
addr.field_size = s_input_len*sizeof(*scratch);
addr.no_elements = s_input_len;
addr.pfield = (void*)scratch;
testDiag("Test dbPutConvertRoutine[DBF_SHORT][DBF_SHORT]");
{
testDiag("Copy in first element");
putter(&addr, s_input, 1, s_input_len, 0);
testOk1(scratch[0]==s_input[0]);
memset(scratch, 0x42, sizeof(s_input));
}
{
testDiag("Copy in entire array");
putter(&addr, s_input, s_input_len, s_input_len, 0);
testOk1(memcmp(scratch, s_input, sizeof(s_input))==0);
memset(scratch, 0x42, sizeof(s_input));
}
}
MAIN(testdbConvert)
{
testPlan(16);
testBasicGet();
testBasicPut();
return testDone();
}