Experimental Physics and Industrial Control System
After seeing the conversation about processing large arrays with pyepics, Tom Cobb pointed out to me that we have a similar problem with large arrays in cothread: using cothread.catools.camonitor() on a 1.4MB image (running at 30 fps) only returns a fraction of the available updates when using cothread version 2-3 (or earlier).
In brief:
1. The problem arises as a consequence of using ca_pend_event() in polling mode;
2. I have a fixed version of cothread which can now receive, deliver and process all available updates (1.4MB at 30 fps) which can be downloaded from git at http://controls.diamond.ac.uk/downloads/python/cothread/ (not currently released).
I would be extremely grateful if anybody interested in using this library would take the time to test this version (commit 50e7cfc is current at time of posting this mail).
Note that there is also an incomplete work in progress python3 branch in this repository. Any feedback would be very welcome.
1/ Using ca_pend_event()
The attached file timing.c runs CA with preemptive callbacks disabled to subscribe to the PV described above (this is a 1.4MB array updating at 30 Hz). If run as shown it will rapidly start dropping most updates, for example:
$ ./timing
Connected: 0x9bf6e00, 6
.....tick: 5
................tick: 16
.tick: 1
.tick: 1
.tick: 1
.tick: 1
.tick: 1
..tick: 2
..tick: 2
make: *** [test] Interrupt
I imagine the problem is that the network buffers are not being cleared properly causing the server to start backing off updates.
If on the other the timeout for ca_pend_event() is increased to say 1e-3 then most updates are delivered (though there are occasional bursts of dropouts). If ca_context_create() is called to enable preemptive callbacks then update dropping goes away.
2/ Implications for cothread
Cothread's core CA dispatch loop calls ca_pend_event(1e-9) so it is affected by this issue; I'm surprised this hasn't been noticed before. In the current git repository at http://controls.diamond.ac.uk/downloads/python/cothread/cothread.git linked from http://controls.diamond.ac.uk/downloads/python/cothread/ I have a fix to this issue which works by enabling preemptive callbacks (and coping with the consequences).
Note that this version of cothread continues to hide all threading issues from users of the library and that user's code will never be called preemtively.
--
This e-mail and any attachments may contain confidential, copyright and or privileged material, and are for the use of the intended addressee only. If you are not the intended addressee or an authorised recipient of the addressee please notify us of receipt by returning the e-mail and do not use, copy, retain, distribute or disclose the information in or attached to the e-mail.
Any opinions expressed within this e-mail are those of the individual and not necessarily of Diamond Light Source Ltd.
Diamond Light Source Ltd. cannot guarantee that this e-mail or any attachments are free from viruses and we cannot accept liability for any damage which you may sustain as a result of software viruses which may be transmitted in or with the message.
Diamond Light Source Limited (company no. 4375679). Registered in England and Wales with its registered office at Diamond House, Harwell Science and Innovation Campus, Didcot, Oxfordshire, OX11 0DE, United Kingdom
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <cadef.h>
static chid channel_id;
static evid event_id;
static int updates = 0;
static int64_t start;
static int last_updates = 0;
static int64_t get_time(void)
{
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
return (int64_t) now.tv_sec * 1000000 + now.tv_nsec / 1000;
}
static void on_connect(struct connection_handler_args args)
{
printf("Connected: %p, %ld\n", args.chid, args.op);
}
static void on_update(struct event_handler_args args)
{
printf(".");
fflush(stdout);
updates += 1;
int64_t now = get_time();
if (now - start >= 1000000)
{
printf("tick: %d\n", updates - last_updates);
last_updates = updates;
start = now;
}
}
int main(int argc, const char **argv)
{
int count = 0;
if (argc > 1)
count = atoi(argv[1]);
ca_context_create(ca_disable_preemptive_callback);
ca_create_channel(
"ARAVISCAM1:ARR:ArrayData", on_connect, NULL, 0, &channel_id);
ca_create_subscription(
DBR_CHAR, count, channel_id, DBE_VALUE, on_update, NULL, &event_id);
start = get_time();
while (true)
{
ca_pend_event(1e-9);
usleep(10000);
}
return 0;
}
- Replies:
- Re: Strategies for working with fast-changing large arrays Matt Newville
- References:
- Re: pyepics: Strategies for working with fast-changing large arrays Anton Derbenev
- Re: pyepics: Strategies for working with fast-changing large arrays Andrew Johnson
- Navigate by Date:
- Prev:
Re: StripTool equivalent in Qt? Mark Davis
- Next:
Re: RTEMS-MVME2300 Janet Anderson
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: pyepics: Strategies for working with fast-changing large arrays Matt Newville
- Next:
Re: Strategies for working with fast-changing large arrays Matt Newville
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024