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 MAXDELAY 16
|
||||
#define INVALID 0xFFFFFFFF
|
||||
|
||||
#define EXITCODE(rc) \
|
||||
( \
|
||||
@ -50,6 +51,8 @@ typedef struct oceanic_atom2_device_t {
|
||||
serial_t *port;
|
||||
unsigned int delay;
|
||||
unsigned int bigpage;
|
||||
unsigned char cache[256];
|
||||
unsigned int cached;
|
||||
} 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);
|
||||
@ -476,6 +479,8 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
|
||||
device->port = NULL;
|
||||
device->delay = 0;
|
||||
device->bigpage = 1; // no big pages
|
||||
device->cached = INVALID;
|
||||
memset(device->cache, 0, sizeof(device->cache));
|
||||
|
||||
// Open the device.
|
||||
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;
|
||||
while (nbytes < size) {
|
||||
// Read the package.
|
||||
unsigned int page = address / pagesize;
|
||||
unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode.
|
||||
unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands.
|
||||
unsigned char command[4] = {read_cmd,
|
||||
(number >> 8) & 0xFF, // high
|
||||
(number ) & 0xFF, // low
|
||||
0};
|
||||
dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), answer, pagesize + crc_size, crc_size);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
if (page != device->cached) {
|
||||
// Read the package.
|
||||
unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode.
|
||||
unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands.
|
||||
unsigned char command[4] = {read_cmd,
|
||||
(number >> 8) & 0xFF, // high
|
||||
(number ) & 0xFF, // low
|
||||
0};
|
||||
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 length = pagesize - offset;
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
memcpy (data, answer + offset, length);
|
||||
memcpy (data, device->cache + offset, length);
|
||||
|
||||
nbytes += length;
|
||||
address += length;
|
||||
@ -701,6 +712,9 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u
|
||||
(size % PAGESIZE != 0))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Invalidate the cache.
|
||||
device->cached = INVALID;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
// Prepare to write the package.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user