Skip to content

Commit

Permalink
Preheat cache for UDP/IP devices.
Browse files Browse the repository at this point in the history
This helps paralleize parts of the initialization process that would
otherwise happen in a serial fashion.

In tests with an IOC controlling one EVG and six EVRs, this reduced the
startup time from 80 to 14 seconds.
  • Loading branch information
smarsching committed Jun 12, 2021
1 parent d908207 commit 93e9ee7
Show file tree
Hide file tree
Showing 5 changed files with 443 additions and 6 deletions.
30 changes: 30 additions & 0 deletions mrfApp/mrfEpicsSrc/MrfMemoryCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ MrfMemoryCache::MrfMemoryCache(std::shared_ptr<MrfMemoryAccess> memoryAccess) :
memoryAccess(*memoryAccess), memoryAccessPtr(memoryAccess) {
}

std::map<std::uint32_t, std::uint16_t> MrfMemoryCache::getCacheUInt16() const {
// Access to the hash map has to be protected by a mutex.
std::lock_guard<std::recursive_mutex> lock(mutex);
return std::map<std::uint32_t, std::uint16_t>(
cacheUInt16.begin(), cacheUInt16.end());
}

std::map<std::uint32_t, std::uint32_t> MrfMemoryCache::getCacheUInt32() const {
// Access to the hash map has to be protected by a mutex.
std::lock_guard<std::recursive_mutex> lock(mutex);
return std::map<std::uint32_t, std::uint32_t>(
cacheUInt32.begin(), cacheUInt32.end());
}

std::uint16_t MrfMemoryCache::readUInt16(std::uint32_t address) {
{
// Access to the hash map has to be protected by a mutex.
Expand Down Expand Up @@ -91,6 +105,22 @@ std::uint32_t MrfMemoryCache::readUInt32(std::uint32_t address) {
}
}

void MrfMemoryCache::tryCacheUInt16(std::uint32_t address) {
try {
readUInt16(address);
} catch (...) {
// We ignore any exception.
}
}

void MrfMemoryCache::tryCacheUInt32(std::uint32_t address) {
try {
readUInt32(address);
} catch (...) {
// We ignore any exception.
}
}

}
}
}
37 changes: 36 additions & 1 deletion mrfApp/mrfEpicsSrc/MrfMemoryCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define ANKA_MRF_EPICS_MEMORY_CACHE_H

#include <cstdint>
#include <map>
#include <mutex>
#include <unordered_map>

Expand Down Expand Up @@ -70,6 +71,24 @@ class MrfMemoryCache {
*/
explicit MrfMemoryCache(std::shared_ptr<MrfMemoryAccess> memoryAccess);

/**
* Returns a snapshot of the cache for uint16 values. The returned map is a
* copy of the cache at the time of calling this method and does not receive
* any subsequent updates. This method is primarily intended for diagnostic
* purposes. The returned map contains memory addresses as keys and the
* respective cached values as values.
*/
std::map<std::uint32_t, std::uint16_t> getCacheUInt16() const;

/**
* Returns a snapshot of the cache for uint32 values. The returned map is a
* copy of the cache at the time of calling this method and does not receive
* any subsequent updates. This method is primarily intended for diagnostic
* purposes. The returned map contains memory addresses as keys and the
* respective cached values as values.
*/
std::map<std::uint32_t, std::uint32_t> getCacheUInt32() const;

/**
* Reads from an unsigned 16-bit register. The method blocks until the
* operation has finished (either successfully or unsuccessfully). On success,
Expand All @@ -92,6 +111,22 @@ class MrfMemoryCache {
*/
std::uint32_t readUInt32(std::uint32_t address);

/**
* Tries to read an unsigned 16-bit register. If the read attempt fails, the
* error is silently ignored. This method is intended to warm up the cache, so
* that subsequent read requests for the same address can be served from the
* cache.
*/
void tryCacheUInt16(std::uint32_t address);

/**
* Tries to read an unsigned 32-bit register. If the read attempt fails, the
* error is silently ignored. This method is intended to warm up the cache, so
* that subsequent read requests for the same address can be served from the
* cache.
*/
void tryCacheUInt32(std::uint32_t address);

private:

// We do not want to allow copy or move construction or assignment.
Expand All @@ -103,7 +138,7 @@ class MrfMemoryCache {
MrfMemoryAccess &memoryAccess;
std::shared_ptr<MrfMemoryAccess> memoryAccessPtr;

std::recursive_mutex mutex;
mutable std::recursive_mutex mutex;

std::unordered_map<std::uint32_t, std::uint16_t> cacheUInt16;
std::unordered_map<std::uint32_t, std::uint32_t> cacheUInt32;
Expand Down
56 changes: 56 additions & 0 deletions mrfApp/mrfEpicsSrc/mrfRegistrarCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
*/

#include <climits>
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <memory>
#include <mutex>
Expand Down Expand Up @@ -110,6 +112,59 @@ void mapInterruptToEvent(const std::string &deviceId, int eventNumber,

extern "C" {

// Data structures needed for the iocsh mrfDumpCache function.
static const iocshArg iocshMrfDumpCacheArg0 = { "device ID", iocshArgString };
static const iocshArg * const iocshMrfDumpCacheArgs[] = {
&iocshMrfDumpCacheArg0 };
static const iocshFuncDef iocshMrfDumpCacheFuncDef = {
"mrfDumpCache", 1, iocshMrfDumpCacheArgs };

/**
* Implementation of the iocsh mrfDumpCache function. This function prints the
* contents of the memory cache for a device. It is mainly intended for
* diagnostics when developing this device support. In particular, it is used to
* get a list of addresses for which the cache is used.
*/
static void iocshMrfDumpCacheFunc(const iocshArgBuf *args) noexcept {
char *deviceId = args[0].sval;
// Verify and convert the parameters.
if (!deviceId) {
errorPrintf(
"Device ID must be specified.");
return;
}
if (!std::strlen(deviceId)) {
errorPrintf(
"Device ID must not be empty.");
return;
}
try {
auto cache = MrfDeviceRegistry::getInstance().getDeviceCache(deviceId);
if (!cache) {
errorPrintf("Could not find cache for device with ID \"%s\".", deviceId);
return;
}
std::printf("uint16 registers:\n\n");
for (auto &addressAndValue : cache->getCacheUInt16()) {
std::printf(
"0x%08" PRIx32 ": 0x%04" PRIx16 "\n",
addressAndValue.first,
addressAndValue.second);
}
std::printf("\n\nuint32 registers:\n\n");
for (auto &addressAndValue : cache->getCacheUInt32()) {
std::printf(
"0x%08" PRIx32 ": 0x%08" PRIx32 "\n",
addressAndValue.first,
addressAndValue.second);
}
} catch (std::exception &e) {
errorPrintf("Error while accessing device cache: %s", e.what());
} catch (...) {
errorPrintf("Error while accessing device cache: Unknown error.");
}
}

// Data structures needed for the iocsh mrfMapInterruptToEvent function.
static const iocshArg iocshMrfMapInterruptToEventArg0 = { "device ID",
iocshArgString };
Expand Down Expand Up @@ -204,6 +259,7 @@ static void iocshMrfMapInterruptToEventFunc(const iocshArgBuf *args) noexcept {
* Registrar that registers the iocsh commands.
*/
static void mrfRegistrarCommon() {
::iocshRegister(&iocshMrfDumpCacheFuncDef, iocshMrfDumpCacheFunc);
::iocshRegister(&iocshMrfMapInterruptToEventFuncDef,
iocshMrfMapInterruptToEventFunc);
}
Expand Down
Loading

0 comments on commit 93e9ee7

Please sign in to comment.