Merge lp:~epics-core/epics-base/compress into lp:~epics-core/epics-base/3.16
- compress
- Merge into 3.16
Status: | Merged |
---|---|
Merged at revision: | 12715 |
Proposed branch: | lp:~epics-core/epics-base/compress |
Merge into: | lp:~epics-core/epics-base/3.16 |
Diff against target: |
680 lines (+459/-37) 9 files modified
documentation/RELEASE_NOTES.html (+6/-0) src/ioc/db/dbAccess.c (+5/-5) src/std/filters/arr.c (+2/-2) src/std/rec/compressRecord.c (+43/-24) src/std/rec/compressRecord.dbd.pod (+35/-6) src/std/rec/test/Makefile (+7/-0) src/std/rec/test/compressTest.c (+351/-0) src/std/rec/test/compressTest.db (+7/-0) src/std/rec/test/epicsRunRecordTests.c (+3/-0) |
To merge this branch: | bzr merge lp:~epics-core/epics-base/compress |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Approve | ||
mdavidsaver | Approve | ||
Ralph Lange | Pending | ||
Review via email: mp+282534@code.launchpad.net |
This proposal supersedes a proposal from 2014-08-28.
Commit message
Description of the change
From Kukhee Kim
- Implement LIFO behavior in compress record
- Prepare new field BALG (Buffering Algorithm) to allow to choose FIFO and LIFO
From Michael Davidsaver
I've rebased against the current 3.16 branch and added unit testing of (only) circular buffer mode with FIFO and LIFO ordering.
In the process of writing the test I found that before the buffer is filled (nuse<nsam) the first nsam-nuse elements are visible as zeros. I didn't like this and changed the handling of OFF in compressRecord and in of no_elements in dbGet to avoid it.
So the changes which need the most attention are to dbGet() and the arr filter. These changes switch from wrapping around based on the number of valid elements set by rset::get_
This should only be a change where offset>0 and the buffer is not full. Given that this didn't work quite right before (could wrap one element early) I'm guessing that no existing code intentionally depends on this.
Kim, Kukhee (khkim) wrote : Posted in a previous version of this proposal | # |
mdavidsaver (mdavidsaver) wrote : Posted in a previous version of this proposal | # |
What should be done about switching between FIFO and LIFO at runtime? At present LIFO -> FIFO clears the buffer. FIFO -> LIFO can't clear the buffer, but could zero it. Alternately, make the BALG field read only somehow.
Otherwise this works as I expect.
To save Andrew the trouble, please add to RELEASE_NOTES.html
mdavidsaver (mdavidsaver) wrote : Posted in a previous version of this proposal | # |
Zeroing the buffer on reset seems sufficient.
As for epicsThreadVali
Also, I'm commenting now because I've just noticed that there was activity on this branch. Since launchpad is sparing with email notifications it's a good idea to send a note to core-talk when pushing changes to a branch after a long period of inactivity.
Ralph Lange (ralph-lange) wrote : Posted in a previous version of this proposal | # |
Should have some tests added, shouldn't it?
Andrew Johnson (anj) wrote : Posted in a previous version of this proposal | # |
Results of AJ+MD+RL discussion about this today:
* This should be a 3.16 change (3.16.0.2 maybe), not 3.15.
* Needs Release Notes entry and POD documentation for the new field (AJ?).
* Remove the epicsThreadVali
* Automated tests would be nice given the complexity of the record, but we will accept the change without them.
mdavidsaver (mdavidsaver) wrote : | # |
Rebased only compressRecord changes against 3.16. Added unittest and a change to dbGet().
@AJ/RL I know I was the one pushing to wave the unittest requirement for this change, but on reflection I've changed my mind. Testing recordtype logic is now straightforward. Not doing so is just laziness. I'll save the waiver argument for rsrv interface binding, where unittesting isn't straightforward.
As for the change to dbGet()... I have to admit this was a case of scope creep.
- 12708. By mdavidsaver
-
update release notes
Andrew Johnson (anj) wrote : | # |
Merging after some minor source reformatting.
Preview Diff
1 | === modified file 'documentation/RELEASE_NOTES.html' |
2 | --- documentation/RELEASE_NOTES.html 2015-09-07 19:23:04 +0000 |
3 | +++ documentation/RELEASE_NOTES.html 2016-01-14 02:46:51 +0000 |
4 | @@ -20,6 +20,12 @@ |
5 | |
6 | --> |
7 | |
8 | +<h3>compressRecord buffering order</h3> |
9 | + |
10 | +<p>The compressRecord has a new field <em>BALG</em> which can select between |
11 | +FIFO (append) and LIFO (prepend) ordering for insertion of new elements. |
12 | +FIFO ordering is the default.</p> |
13 | + |
14 | <h3>Database Multi-locking</h3> |
15 | |
16 | <p>dbLock.c is re-written with an expanded API, and the removal of global mutex locks.</p> |
17 | |
18 | === modified file 'src/ioc/db/dbAccess.c' |
19 | --- src/ioc/db/dbAccess.c 2015-09-07 04:15:21 +0000 |
20 | +++ src/ioc/db/dbAccess.c 2016-01-14 02:46:51 +0000 |
21 | @@ -816,7 +816,7 @@ |
22 | void *pfieldsave; |
23 | db_field_log *pfl = (db_field_log *)pflin; |
24 | short field_type; |
25 | - long no_elements; |
26 | + long no_elements, max_elements; |
27 | long offset; |
28 | struct rset *prset; |
29 | long status = 0; |
30 | @@ -828,10 +828,10 @@ |
31 | |
32 | if (!pfl || pfl->type == dbfl_type_rec) { |
33 | field_type = paddr->field_type; |
34 | - no_elements = paddr->no_elements; |
35 | + max_elements = no_elements = paddr->no_elements; |
36 | } else { |
37 | field_type = pfl->field_type; |
38 | - no_elements = pfl->no_elements; |
39 | + max_elements = no_elements = pfl->no_elements; |
40 | } |
41 | |
42 | if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) |
43 | @@ -906,7 +906,7 @@ |
44 | if (n <= 0) { |
45 | ;/*do nothing*/ |
46 | } else if (!pfl || pfl->type == dbfl_type_rec) { |
47 | - status = convert(paddr, pbuf, n, no_elements, offset); |
48 | + status = convert(paddr, pbuf, n, max_elements, offset); |
49 | } else { |
50 | DBADDR localAddr = *paddr; /* Structure copy */ |
51 | |
52 | @@ -917,7 +917,7 @@ |
53 | localAddr.pfield = (char *) &pfl->u.v.field; |
54 | else |
55 | localAddr.pfield = (char *) pfl->u.r.field; |
56 | - status = convert(&localAddr, pbuf, n, no_elements, offset); |
57 | + status = convert(&localAddr, pbuf, n, max_elements, offset); |
58 | } |
59 | } |
60 | done: |
61 | |
62 | === modified file 'src/std/filters/arr.c' |
63 | --- src/std/filters/arr.c 2014-09-30 14:19:13 +0000 |
64 | +++ src/std/filters/arr.c 2016-01-14 02:46:51 +0000 |
65 | @@ -95,7 +95,7 @@ |
66 | long end = my->end; |
67 | long nTarget = 0; |
68 | long offset = 0; |
69 | - long nSource = chan->addr.no_elements; |
70 | + long nSource = chan->addr.no_elements, maxSource = nSource; |
71 | |
72 | /* Only array data */ |
73 | if (pfl->type == dbfl_type_val) { |
74 | @@ -126,7 +126,7 @@ |
75 | pfl->u.r.dtor = freeArray; |
76 | pfl->u.r.pvt = my->arrayFreeList; |
77 | offset = (offset + start) % chan->addr.no_elements; |
78 | - dbExtractArrayFromRec(&chan->addr, pdst, nTarget, nSource, offset, my->incr); |
79 | + dbExtractArrayFromRec(&chan->addr, pdst, nTarget, maxSource, offset, my->incr); |
80 | pfl->u.r.field = pdst; |
81 | } |
82 | } |
83 | |
84 | === modified file 'src/std/rec/compressRecord.c' |
85 | --- src/std/rec/compressRecord.c 2013-12-17 18:54:04 +0000 |
86 | +++ src/std/rec/compressRecord.c 2016-01-14 02:46:51 +0000 |
87 | @@ -92,6 +92,8 @@ |
88 | if (prec->alg == compressALG_Average && prec->sptr == 0){ |
89 | prec->sptr = calloc(prec->nsam, sizeof(double)); |
90 | } |
91 | + |
92 | + if(prec->bptr && prec->nsam) memset(prec->bptr, 0, prec->nsam * sizeof(double)); |
93 | } |
94 | |
95 | static void monitor(compressRecord *prec) |
96 | @@ -108,29 +110,32 @@ |
97 | |
98 | static void put_value(compressRecord *prec, double *psource, int n) |
99 | { |
100 | - epicsInt32 offset = prec->off; |
101 | - epicsInt32 nuse = prec->nuse; |
102 | - epicsInt32 nsam = prec->nsam; |
103 | - double *pdest = prec->bptr + offset; |
104 | - int i; |
105 | + int fifo = prec->balg==bufferingALG_FIFO; |
106 | + epicsUInt32 offset = prec->off; |
107 | + epicsUInt32 nuse = prec->nuse; |
108 | + epicsUInt32 nsam = prec->nsam; |
109 | |
110 | - for (i = 0; i < n; i++) { |
111 | - *pdest = *psource++; |
112 | - if (++offset >= nsam) { |
113 | - pdest = prec->bptr; |
114 | - offset = 0; |
115 | - } |
116 | - else |
117 | - pdest++; |
118 | - } |
119 | nuse += n; |
120 | - if (nuse > nsam) |
121 | + if(nuse>nsam) |
122 | nuse = nsam; |
123 | + |
124 | + while(n--) { |
125 | + /* for LIFO, decrement before */ |
126 | + if(!fifo) |
127 | + offset = (offset-1)%nsam; |
128 | + |
129 | + prec->bptr[offset] = *psource++; |
130 | + |
131 | + /* for FIFO, increment after */ |
132 | + if(fifo) |
133 | + offset = (offset+1)%nsam; |
134 | + } |
135 | + |
136 | prec->off = offset; |
137 | prec->nuse = nuse; |
138 | - return; |
139 | } |
140 | - |
141 | |
142 | + |
143 | + |
144 | /* qsort comparison function (for median calculation) */ |
145 | static int compare(const void *arg1, const void *arg2) |
146 | { |
147 | @@ -305,6 +310,7 @@ |
148 | prec->bptr = calloc(prec->nsam, sizeof(double)); |
149 | reset(prec); |
150 | } |
151 | + |
152 | return 0; |
153 | } |
154 | |
155 | @@ -388,18 +394,30 @@ |
156 | paddr->field_type = DBF_DOUBLE; |
157 | paddr->field_size = sizeof(double); |
158 | paddr->dbr_field_type = DBF_DOUBLE; |
159 | + |
160 | + if(prec->balg == bufferingALG_LIFO) paddr->special = SPC_NOMOD; |
161 | return 0; |
162 | } |
163 | |
164 | static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) |
165 | { |
166 | + /* offset indicates the next element which would be written. |
167 | + * In FIFO mode offset-1 is the last valid element |
168 | + * In LIFO mode offset is the first valid element |
169 | + * (*offset) should be set to the index of the first valid element |
170 | + */ |
171 | compressRecord *prec = (compressRecord *) paddr->precord; |
172 | - |
173 | - *no_elements = prec->nuse; |
174 | - if (prec->nuse == prec->nsam) |
175 | - *offset = prec->off; |
176 | - else |
177 | - *offset = 0; |
178 | + epicsUInt32 off = prec->off; |
179 | + epicsUInt32 nuse = prec->nuse; |
180 | + epicsUInt32 nsam = prec->nsam; |
181 | + |
182 | + *no_elements = nuse; |
183 | + if(prec->balg == bufferingALG_FIFO) { |
184 | + *offset = (off-nuse)%nsam; |
185 | + } else { |
186 | + *offset = off; |
187 | + } |
188 | + |
189 | return 0; |
190 | } |
191 | |
192 | @@ -407,7 +425,8 @@ |
193 | { |
194 | compressRecord *prec = (compressRecord *) paddr->precord; |
195 | |
196 | - prec->off = (prec->off + nNew) % prec->nsam; |
197 | + if(prec->balg == bufferingALG_FIFO) |
198 | + prec->off = (prec->off + nNew) % prec->nsam; |
199 | prec->nuse += nNew; |
200 | if (prec->nuse > prec->nsam) |
201 | prec->nuse = prec->nsam; |
202 | |
203 | === modified file 'src/std/rec/compressRecord.dbd.pod' |
204 | --- src/std/rec/compressRecord.dbd.pod 2013-09-30 22:48:06 +0000 |
205 | +++ src/std/rec/compressRecord.dbd.pod 2016-01-14 02:46:51 +0000 |
206 | @@ -9,19 +9,37 @@ |
207 | |
208 | =title Compress Record (compress) |
209 | |
210 | -... |
211 | +The data compression record is used to collect and compress data from arrays. |
212 | +When the INP field references a data array field, |
213 | +it immediately compresses the entire array into an element of an array using one of several algorithms, |
214 | +overwriting the previous element. If the INP field obtains its value from a scalar-value field, |
215 | +the compression record will collect a new sample each time the record is processed |
216 | +and add it to the compressed data array as a circular buffer. |
217 | + |
218 | +The INP link can also specify a constant; |
219 | +however, if this is the case, the compression algorithms are ignored, |
220 | +and the record support routines merely return after checking the FLNK field. |
221 | |
222 | =head2 Record-specific Menus |
223 | |
224 | =head3 Menu compressALG |
225 | |
226 | +=menu compressALG |
227 | + |
228 | The ALG field which uses this menu controls the compression algorithm used. |
229 | |
230 | -... |
231 | - |
232 | -=menu compressALG |
233 | - |
234 | -... |
235 | +There are six possible algorithms which can be specified as follows: |
236 | + |
237 | +* Circular Buffer |
238 | +* Average |
239 | +* N to 1 Low Value |
240 | +* N to 1 High Value |
241 | +* N to 1 Average |
242 | +* N to 1 Median |
243 | + |
244 | +=menu bufferingALG |
245 | + |
246 | +Selects FIFO (First in first out) or LIFO (Last in first out) insertion order. |
247 | |
248 | =head2 Parameter Fields |
249 | |
250 | @@ -41,6 +59,10 @@ |
251 | choice(compressALG_Circular_Buffer,"Circular Buffer") |
252 | choice(compressALG_N_to_1_Median,"N to 1 Median") |
253 | } |
254 | +menu(bufferingALG) { |
255 | + choice(bufferingALG_FIFO, "FIFO Buffer") |
256 | + choice(bufferingALG_LIFO, "LIFO Buffer") |
257 | +} |
258 | recordtype(compress) { |
259 | |
260 | =fields VAL |
261 | @@ -76,6 +98,13 @@ |
262 | interest(1) |
263 | menu(compressALG) |
264 | } |
265 | + field(BALG,DBF_MENU) { |
266 | + prompt("Buffering Algorithm") |
267 | + promptgroup(GUI_ALARMS) |
268 | + special(SPC_RESET) |
269 | + interest(1) |
270 | + menu(bufferingALG) |
271 | + } |
272 | field(NSAM,DBF_ULONG) { |
273 | prompt("Number of Values") |
274 | promptgroup(GUI_COMPRESS) |
275 | |
276 | === modified file 'src/std/rec/test/Makefile' |
277 | --- src/std/rec/test/Makefile 2016-01-07 19:22:43 +0000 |
278 | +++ src/std/rec/test/Makefile 2016-01-14 02:46:51 +0000 |
279 | @@ -38,6 +38,13 @@ |
280 | TESTFILES += ../linkRetargetLink.db |
281 | TESTS += linkRetargetLinkTest |
282 | |
283 | +TESTPROD_HOST += compressTest |
284 | +compressTest_SRCS += compressTest.c |
285 | +compressTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp |
286 | +testHarness_SRCS += compressTest.c |
287 | +TESTFILES += ../compressTest.db |
288 | +TESTS += compressTest |
289 | + |
290 | TARGETS += $(COMMON_DIR)/asTestIoc.dbd |
291 | asTestIoc_DBD += base.dbd |
292 | asTestIoc_DBD += asTest.dbd |
293 | |
294 | === added file 'src/std/rec/test/compressTest.c' |
295 | --- src/std/rec/test/compressTest.c 1970-01-01 00:00:00 +0000 |
296 | +++ src/std/rec/test/compressTest.c 2016-01-14 02:46:51 +0000 |
297 | @@ -0,0 +1,351 @@ |
298 | +/*************************************************************************\ |
299 | +* Copyright (c) 2016 Michael Davidsaver |
300 | +* EPICS BASE is distributed subject to a Software License Agreement found |
301 | +* in file LICENSE that is included with this distribution. |
302 | +\*************************************************************************/ |
303 | + |
304 | +#include "dbUnitTest.h" |
305 | +#include "testMain.h" |
306 | +#include "dbLock.h" |
307 | +#include "errlog.h" |
308 | +#include "dbAccess.h" |
309 | +#include "epicsMath.h" |
310 | + |
311 | +#include "aiRecord.h" |
312 | +#include "compressRecord.h" |
313 | + |
314 | +#define testDEq(A,B,D) testOk(fabs((A)-(B))<(D), #A " (%f) ~= " #B " (%f)", A, B) |
315 | + |
316 | +void recTestIoc_registerRecordDeviceDriver(struct dbBase *); |
317 | + |
318 | +static |
319 | +void checkArrD(const char *pv, long elen, double a, double b, double c, double d) |
320 | +{ |
321 | + double buf[4]; |
322 | + double expect[4]; |
323 | + long nReq = NELEMENTS(buf), i; |
324 | + unsigned match; |
325 | + DBADDR addr; |
326 | + |
327 | + expect[0] = a; |
328 | + expect[1] = b; |
329 | + expect[2] = c; |
330 | + expect[3] = d; |
331 | + |
332 | + if(dbNameToAddr(pv, &addr)) |
333 | + testAbort("Unknown PV '%s'", pv); |
334 | + |
335 | + if(dbGet(&addr, DBR_DOUBLE, buf, NULL, &nReq, NULL)) |
336 | + testAbort("Failed to get '%s'", pv); |
337 | + |
338 | + match = elen==nReq; |
339 | + for(i=0; i<nReq && i<elen; i++) { |
340 | + match &= fabs(buf[i]-expect[i])<0.01; |
341 | + } |
342 | + testOk(match, "dbGet(\"%s\") matches", pv); |
343 | + if(elen!=nReq) |
344 | + testDiag("lengths don't match %ld != %ld", elen, nReq); |
345 | + for(i=0; i<nReq && i<elen; i++) { |
346 | + if(fabs(buf[i]-expect[i])>=0.01) |
347 | + testDiag("[%ld] -> %f != %f", i, expect[i], buf[i]); |
348 | + } |
349 | +} |
350 | + |
351 | +static |
352 | +void checkArrI(const char *pv, long elen, epicsInt32 a, epicsInt32 b, epicsInt32 c, epicsInt32 d) |
353 | +{ |
354 | + epicsInt32 buf[4]; |
355 | + epicsInt32 expect[4]; |
356 | + long nReq = NELEMENTS(buf), i; |
357 | + unsigned match; |
358 | + DBADDR addr; |
359 | + |
360 | + expect[0] = a; |
361 | + expect[1] = b; |
362 | + expect[2] = c; |
363 | + expect[3] = d; |
364 | + |
365 | + if(dbNameToAddr(pv, &addr)) |
366 | + testAbort("Unknown PV '%s'", pv); |
367 | + |
368 | + if(dbGet(&addr, DBR_LONG, buf, NULL, &nReq, NULL)) |
369 | + testAbort("Failed to get '%s'", pv); |
370 | + |
371 | + match = elen==nReq; |
372 | + for(i=0; i<nReq && i<elen; i++) { |
373 | + match &= buf[i]==expect[i]; |
374 | + } |
375 | + testOk(match, "dbGet(\"%s\") matches", pv); |
376 | + if(elen!=nReq) |
377 | + testDiag("lengths don't match %ld != %ld", elen, nReq); |
378 | + for(i=0; i<nReq && i<elen; i++) { |
379 | + if(buf[i]!=expect[i]) |
380 | + testDiag("[%ld] -> %d != %d", i, (int)expect[i], (int)buf[i]); |
381 | + } |
382 | +} |
383 | + |
384 | +static |
385 | +void testFIFOCirc(void) |
386 | +{ |
387 | + aiRecord *vrec; |
388 | + compressRecord *crec; |
389 | + double *cbuf; |
390 | + |
391 | + testDiag("Test FIFO"); |
392 | + |
393 | + testdbPrepare(); |
394 | + |
395 | + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); |
396 | + |
397 | + recTestIoc_registerRecordDeviceDriver(pdbbase); |
398 | + |
399 | + testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=FIFO Buffer,NSAM=4"); |
400 | + |
401 | + vrec = (aiRecord*)testdbRecordPtr("val"); |
402 | + crec = (compressRecord*)testdbRecordPtr("comp"); |
403 | + |
404 | + eltc(0); |
405 | + testIocInitOk(); |
406 | + eltc(1); |
407 | + |
408 | + dbScanLock((dbCommon*)crec); |
409 | + cbuf = crec->bptr; |
410 | + |
411 | + testOk1(crec->off==0); |
412 | + testOk1(crec->inx==0); |
413 | + testOk1(crec->nuse==0); |
414 | + |
415 | + testDiag("Push 1.1"); |
416 | + vrec->val = 1.1; |
417 | + dbProcess((dbCommon*)crec); |
418 | + |
419 | + /* In FIFO mode the valid elements a cbuf[(off-nuse-1)%size] through cbuf[(off-1)%size] */ |
420 | + testOk1(crec->off==1); |
421 | + testOk1(crec->inx==0); |
422 | + testOk1(crec->nuse==1); |
423 | + testDEq(cbuf[0], 1.1, 0.1); |
424 | + testDEq(cbuf[1], 0.0, 0.1); |
425 | + testDEq(cbuf[2], 0.0, 0.1); |
426 | + testDEq(cbuf[3], 0.0, 0.1); |
427 | + checkArrD("comp", 1, 1.1, 0, 0, 0); |
428 | + |
429 | + testDiag("Push 2.1"); |
430 | + vrec->val = 2.1; |
431 | + dbProcess((dbCommon*)crec); |
432 | + |
433 | + testOk1(crec->off==2); |
434 | + testOk1(crec->inx==0); |
435 | + testOk1(crec->nuse==2); |
436 | + testDEq(cbuf[0], 1.1, 0.1); |
437 | + testDEq(cbuf[1], 2.1, 0.1); |
438 | + testDEq(cbuf[2], 0.0, 0.1); |
439 | + testDEq(cbuf[3], 0.0, 0.1); |
440 | + checkArrD("comp", 2, 1.1, 2.1, 0, 0); |
441 | + |
442 | + testDiag("Push 3.1"); |
443 | + vrec->val = 3.1; |
444 | + dbProcess((dbCommon*)crec); |
445 | + |
446 | + testOk1(crec->off==3); |
447 | + testOk1(crec->inx==0); |
448 | + testOk1(crec->nuse==3); |
449 | + testDEq(cbuf[0], 1.1, 0.1); |
450 | + testDEq(cbuf[1], 2.1, 0.1); |
451 | + testDEq(cbuf[2], 3.1, 0.1); |
452 | + testDEq(cbuf[3], 0.0, 0.1); |
453 | + checkArrD("comp", 3, 1.1, 2.1, 3.1, 0); |
454 | + |
455 | + testDiag("Push 4.1"); |
456 | + vrec->val = 4.1; |
457 | + dbProcess((dbCommon*)crec); |
458 | + |
459 | + testOk1(crec->off==0); |
460 | + testOk1(crec->inx==0); |
461 | + testOk1(crec->nuse==4); |
462 | + testDEq(cbuf[0], 1.1, 0.1); |
463 | + testDEq(cbuf[1], 2.1, 0.1); |
464 | + testDEq(cbuf[2], 3.1, 0.1); |
465 | + testDEq(cbuf[3], 4.1, 0.1); |
466 | + checkArrD("comp", 4, 1.1, 2.1, 3.1, 4.1); |
467 | + |
468 | + testDiag("Push 5.1"); |
469 | + vrec->val = 5.1; |
470 | + dbProcess((dbCommon*)crec); |
471 | + |
472 | + testOk1(crec->off==1); |
473 | + testOk1(crec->inx==0); |
474 | + testOk1(crec->nuse==4); |
475 | + testDEq(cbuf[0], 5.1, 0.1); |
476 | + testDEq(cbuf[1], 2.1, 0.1); |
477 | + testDEq(cbuf[2], 3.1, 0.1); |
478 | + testDEq(cbuf[3], 4.1, 0.1); |
479 | + checkArrD("comp", 4, 2.1, 3.1, 4.1, 5.1); |
480 | + |
481 | + testDiag("Push 6.1"); |
482 | + vrec->val = 6.1; |
483 | + dbProcess((dbCommon*)crec); |
484 | + |
485 | + testOk1(crec->off==2); |
486 | + testOk1(crec->inx==0); |
487 | + testOk1(crec->nuse==4); |
488 | + testDEq(cbuf[0], 5.1, 0.1); |
489 | + testDEq(cbuf[1], 6.1, 0.1); |
490 | + testDEq(cbuf[2], 3.1, 0.1); |
491 | + testDEq(cbuf[3], 4.1, 0.1); |
492 | + checkArrD("comp", 4, 3.1, 4.1, 5.1, 6.1); |
493 | + |
494 | + dbScanUnlock((dbCommon*)crec); |
495 | + |
496 | + testDiag("Reset"); |
497 | + testdbPutFieldOk("comp.RES", DBF_LONG, 0); |
498 | + |
499 | + dbScanLock((dbCommon*)crec); |
500 | + testOk1(crec->off==0); |
501 | + testOk1(crec->inx==0); |
502 | + testOk1(crec->nuse==0); |
503 | + checkArrD("comp", 0, 0, 0, 0, 0); |
504 | + dbScanUnlock((dbCommon*)crec); |
505 | + |
506 | + testIocShutdownOk(); |
507 | + |
508 | + testdbCleanup(); |
509 | +} |
510 | + |
511 | +static |
512 | +void testLIFOCirc(void) |
513 | +{ |
514 | + aiRecord *vrec; |
515 | + compressRecord *crec; |
516 | + double *cbuf; |
517 | + |
518 | + testDiag("Test LIFO"); |
519 | + |
520 | + testdbPrepare(); |
521 | + |
522 | + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); |
523 | + |
524 | + recTestIoc_registerRecordDeviceDriver(pdbbase); |
525 | + |
526 | + testdbReadDatabase("compressTest.db", NULL, "ALG=Circular Buffer,BALG=LIFO Buffer,NSAM=4"); |
527 | + |
528 | + vrec = (aiRecord*)testdbRecordPtr("val"); |
529 | + crec = (compressRecord*)testdbRecordPtr("comp"); |
530 | + |
531 | + eltc(0); |
532 | + testIocInitOk(); |
533 | + eltc(1); |
534 | + |
535 | + dbScanLock((dbCommon*)crec); |
536 | + cbuf = crec->bptr; |
537 | + |
538 | + testOk1(crec->off==0); |
539 | + testOk1(crec->inx==0); |
540 | + testOk1(crec->nuse==0); |
541 | + |
542 | + testDiag("Push 1.1"); |
543 | + vrec->val = 1.1; |
544 | + dbProcess((dbCommon*)crec); |
545 | + |
546 | + testDiag("off %u", crec->off); |
547 | + testOk1(crec->off==3); |
548 | + testOk1(crec->inx==0); |
549 | + testOk1(crec->nuse==1); |
550 | + testDEq(cbuf[0], 0.0, 0.1); |
551 | + testDEq(cbuf[1], 0.0, 0.1); |
552 | + testDEq(cbuf[2], 0.0, 0.1); |
553 | + testDEq(cbuf[3], 1.1, 0.1); |
554 | + checkArrD("comp", 1, 1.1, 0, 0, 0); |
555 | + |
556 | + testDiag("Push 2.1"); |
557 | + vrec->val = 2.1; |
558 | + dbProcess((dbCommon*)crec); |
559 | + |
560 | + testOk1(crec->off==2); |
561 | + testOk1(crec->inx==0); |
562 | + testOk1(crec->nuse==2); |
563 | + testDEq(cbuf[0], 0.0, 0.1); |
564 | + testDEq(cbuf[1], 0.0, 0.1); |
565 | + testDEq(cbuf[2], 2.1, 0.1); |
566 | + testDEq(cbuf[3], 1.1, 0.1); |
567 | + checkArrD("comp", 2, 2.1, 1.1, 0, 0); |
568 | + checkArrI("comp", 2, 2, 1, 0, 0); |
569 | + |
570 | + testDiag("Push 3.1"); |
571 | + vrec->val = 3.1; |
572 | + dbProcess((dbCommon*)crec); |
573 | + |
574 | + testOk1(crec->off==1); |
575 | + testOk1(crec->inx==0); |
576 | + testOk1(crec->nuse==3); |
577 | + testDEq(cbuf[0], 0.0, 0.1); |
578 | + testDEq(cbuf[1], 3.1, 0.1); |
579 | + testDEq(cbuf[2], 2.1, 0.1); |
580 | + testDEq(cbuf[3], 1.1, 0.1); |
581 | + checkArrD("comp", 3, 3.1, 2.1, 1.1, 0); |
582 | + checkArrI("comp", 3, 3, 2, 1, 0); |
583 | + |
584 | + testDiag("Push 4.1"); |
585 | + vrec->val = 4.1; |
586 | + dbProcess((dbCommon*)crec); |
587 | + |
588 | + testOk1(crec->off==0); |
589 | + testOk1(crec->inx==0); |
590 | + testOk1(crec->nuse==4); |
591 | + testDEq(cbuf[0], 4.1, 0.1); |
592 | + testDEq(cbuf[1], 3.1, 0.1); |
593 | + testDEq(cbuf[2], 2.1, 0.1); |
594 | + testDEq(cbuf[3], 1.1, 0.1); |
595 | + checkArrD("comp", 4, 4.1, 3.1, 2.1, 1.1); |
596 | + checkArrI("comp", 4, 4, 3, 2, 1); |
597 | + |
598 | + testDiag("Push 5.1"); |
599 | + vrec->val = 5.1; |
600 | + dbProcess((dbCommon*)crec); |
601 | + |
602 | + testOk1(crec->off==3); |
603 | + testOk1(crec->inx==0); |
604 | + testOk1(crec->nuse==4); |
605 | + testDEq(cbuf[0], 4.1, 0.1); |
606 | + testDEq(cbuf[1], 3.1, 0.1); |
607 | + testDEq(cbuf[2], 2.1, 0.1); |
608 | + testDEq(cbuf[3], 5.1, 0.1); |
609 | + checkArrD("comp", 4, 5.1, 4.1, 3.1, 2.1); |
610 | + checkArrI("comp", 4, 5, 4, 3, 2); |
611 | + |
612 | + testDiag("Push 6.1"); |
613 | + vrec->val = 6.1; |
614 | + dbProcess((dbCommon*)crec); |
615 | + |
616 | + testOk1(crec->off==2); |
617 | + testOk1(crec->inx==0); |
618 | + testOk1(crec->nuse==4); |
619 | + testDEq(cbuf[0], 4.1, 0.1); |
620 | + testDEq(cbuf[1], 3.1, 0.1); |
621 | + testDEq(cbuf[2], 6.1, 0.1); |
622 | + testDEq(cbuf[3], 5.1, 0.1); |
623 | + checkArrD("comp", 4, 6.1, 5.1, 4.1, 3.1); |
624 | + |
625 | + dbScanUnlock((dbCommon*)crec); |
626 | + |
627 | + testDiag("Reset"); |
628 | + testdbPutFieldOk("comp.RES", DBF_LONG, 0); |
629 | + |
630 | + dbScanLock((dbCommon*)crec); |
631 | + testOk1(crec->off==0); |
632 | + testOk1(crec->inx==0); |
633 | + testOk1(crec->nuse==0); |
634 | + checkArrD("comp", 0, 0, 0, 0, 0); |
635 | + dbScanUnlock((dbCommon*)crec); |
636 | + |
637 | + testIocShutdownOk(); |
638 | + |
639 | + testdbCleanup(); |
640 | +} |
641 | + |
642 | +MAIN(compressTest) |
643 | +{ |
644 | + testPlan(116); |
645 | + testFIFOCirc(); |
646 | + testLIFOCirc(); |
647 | + return testDone(); |
648 | +} |
649 | |
650 | === added file 'src/std/rec/test/compressTest.db' |
651 | --- src/std/rec/test/compressTest.db 1970-01-01 00:00:00 +0000 |
652 | +++ src/std/rec/test/compressTest.db 2016-01-14 02:46:51 +0000 |
653 | @@ -0,0 +1,7 @@ |
654 | +record(ai, "val") {} |
655 | +record(compress, "comp") { |
656 | + field(INP, "val NPP") |
657 | + field(ALG, "$(ALG)") |
658 | + field(BALG,"$(BALG)") |
659 | + field(NSAM,"$(NSAM)") |
660 | +} |
661 | |
662 | === modified file 'src/std/rec/test/epicsRunRecordTests.c' |
663 | --- src/std/rec/test/epicsRunRecordTests.c 2015-08-27 16:13:49 +0000 |
664 | +++ src/std/rec/test/epicsRunRecordTests.c 2016-01-14 02:46:51 +0000 |
665 | @@ -13,6 +13,7 @@ |
666 | #include "epicsExit.h" |
667 | |
668 | int analogMonitorTest(void); |
669 | +int compressTest(void); |
670 | int arrayOpTest(void); |
671 | int asTest(void); |
672 | int linkRetargetLinkTest(void); |
673 | @@ -23,6 +24,8 @@ |
674 | |
675 | runTest(analogMonitorTest); |
676 | |
677 | + runTest(compressTest); |
678 | + |
679 | runTest(arrayOpTest); |
680 | |
681 | runTest(asTest); |
Revision 12520 - 12523
Add epics thread id validation routine
Modify epicsThreadGetName to check up if the thread id is valid to avoid crash
Modify epicsThreadResume() command to avoid crash when user inputs an invalid thread id