Cache the last page to reduce the number of I/O operations.
In bigpage mode, we always read large pages, regardless of the amount of bytes requested by the caller. Excess bytes are simply discarded. This is inefficient because the same large page will be downloaded multiple times, when requesting more than one 16 byte page from the same large page. By caching the pages internally, we can greatly reduce the amount of I/O operations. In practice, applications and also libdivecomputer's internal algorithm for downloading the dives will typically request contiguous pages, so we only need to cache the last page. This implementation is based on ideas and code contributed by Dirk Hohndel.
This commit is contained in:
parent
0bcee519e0
commit
a1ff11e08e
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#define MAXRETRIES 2
|
#define MAXRETRIES 2
|
||||||
#define MAXDELAY 16
|
#define MAXDELAY 16
|
||||||
|
#define INVALID 0xFFFFFFFF
|
||||||
|
|
||||||
#define EXITCODE(rc) \
|
#define EXITCODE(rc) \
|
||||||
( \
|
( \
|
||||||
@ -50,6 +51,8 @@ typedef struct oceanic_atom2_device_t {
|
|||||||
serial_t *port;
|
serial_t *port;
|
||||||
unsigned int delay;
|
unsigned int delay;
|
||||||
unsigned int bigpage;
|
unsigned int bigpage;
|
||||||
|
unsigned char cache[256];
|
||||||
|
unsigned int cached;
|
||||||
} oceanic_atom2_device_t;
|
} oceanic_atom2_device_t;
|
||||||
|
|
||||||
static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||||
@ -476,6 +479,8 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
|
|||||||
device->port = NULL;
|
device->port = NULL;
|
||||||
device->delay = 0;
|
device->delay = 0;
|
||||||
device->bigpage = 1; // no big pages
|
device->bigpage = 1; // no big pages
|
||||||
|
device->cached = INVALID;
|
||||||
|
memset(device->cache, 0, sizeof(device->cache));
|
||||||
|
|
||||||
// Open the device.
|
// Open the device.
|
||||||
int rc = serial_open (&device->port, context, name);
|
int rc = serial_open (&device->port, context, name);
|
||||||
@ -664,24 +669,30 @@ oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned
|
|||||||
|
|
||||||
unsigned int nbytes = 0;
|
unsigned int nbytes = 0;
|
||||||
while (nbytes < size) {
|
while (nbytes < size) {
|
||||||
// Read the package.
|
|
||||||
unsigned int page = address / pagesize;
|
unsigned int page = address / pagesize;
|
||||||
unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode.
|
if (page != device->cached) {
|
||||||
unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands.
|
// Read the package.
|
||||||
unsigned char command[4] = {read_cmd,
|
unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode.
|
||||||
(number >> 8) & 0xFF, // high
|
unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands.
|
||||||
(number ) & 0xFF, // low
|
unsigned char command[4] = {read_cmd,
|
||||||
0};
|
(number >> 8) & 0xFF, // high
|
||||||
dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), answer, pagesize + crc_size, crc_size);
|
(number ) & 0xFF, // low
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
0};
|
||||||
return rc;
|
dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), answer, pagesize + crc_size, crc_size);
|
||||||
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// Cache the page.
|
||||||
|
memcpy (device->cache, answer, pagesize);
|
||||||
|
device->cached = page;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int offset = address % pagesize;
|
unsigned int offset = address % pagesize;
|
||||||
unsigned int length = pagesize - offset;
|
unsigned int length = pagesize - offset;
|
||||||
if (nbytes + length > size)
|
if (nbytes + length > size)
|
||||||
length = size - nbytes;
|
length = size - nbytes;
|
||||||
|
|
||||||
memcpy (data, answer + offset, length);
|
memcpy (data, device->cache + offset, length);
|
||||||
|
|
||||||
nbytes += length;
|
nbytes += length;
|
||||||
address += length;
|
address += length;
|
||||||
@ -701,6 +712,9 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u
|
|||||||
(size % PAGESIZE != 0))
|
(size % PAGESIZE != 0))
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
|
// Invalidate the cache.
|
||||||
|
device->cached = INVALID;
|
||||||
|
|
||||||
unsigned int nbytes = 0;
|
unsigned int nbytes = 0;
|
||||||
while (nbytes < size) {
|
while (nbytes < size) {
|
||||||
// Prepare to write the package.
|
// Prepare to write the package.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user