From 7d4c2a98b6d8b1b85337c2b3d3c2fbb5a2efd102 Mon Sep 17 00:00:00 2001 From: Matt Stancliff Date: Tue, 17 Jun 2014 10:42:19 -0400 Subject: [PATCH 1/2] Add maxmemory_policy to INFO output Also refactors getting human string values from the defined value in `server.maxmemory_policy` into a common function. --- src/config.c | 27 +++++++++++++++------------ src/redis.c | 7 +++++-- src/redis.h | 1 + 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/config.c b/src/config.c index 05cb7c9f..2140b769 100644 --- a/src/config.c +++ b/src/config.c @@ -1004,6 +1004,20 @@ badfmt: /* Bad format errors */ } \ } while(0); +char *maxmemoryToString() { + char *s; + switch(server.maxmemory_policy) { + case REDIS_MAXMEMORY_VOLATILE_LRU: s = "volatile-lru"; break; + case REDIS_MAXMEMORY_VOLATILE_TTL: s = "volatile-ttl"; break; + case REDIS_MAXMEMORY_VOLATILE_RANDOM: s = "volatile-random"; break; + case REDIS_MAXMEMORY_ALLKEYS_LRU: s = "allkeys-lru"; break; + case REDIS_MAXMEMORY_ALLKEYS_RANDOM: s = "allkeys-random"; break; + case REDIS_MAXMEMORY_NO_EVICTION: s = "noeviction"; break; + default: s = "unknown"; break; + } + return s; +} + void configGetCommand(redisClient *c) { robj *o = c->argv[2]; void *replylen = addDeferredMultiBulkLength(c); @@ -1112,19 +1126,8 @@ void configGetCommand(redisClient *c) { matches++; } if (stringmatch(pattern,"maxmemory-policy",0)) { - char *s; - - switch(server.maxmemory_policy) { - case REDIS_MAXMEMORY_VOLATILE_LRU: s = "volatile-lru"; break; - case REDIS_MAXMEMORY_VOLATILE_TTL: s = "volatile-ttl"; break; - case REDIS_MAXMEMORY_VOLATILE_RANDOM: s = "volatile-random"; break; - case REDIS_MAXMEMORY_ALLKEYS_LRU: s = "allkeys-lru"; break; - case REDIS_MAXMEMORY_ALLKEYS_RANDOM: s = "allkeys-random"; break; - case REDIS_MAXMEMORY_NO_EVICTION: s = "noeviction"; break; - default: s = "unknown"; break; /* too harmless to panic */ - } addReplyBulkCString(c,"maxmemory-policy"); - addReplyBulkCString(c,s); + addReplyBulkCString(c,maxmemoryToString()); matches++; } if (stringmatch(pattern,"appendfsync",0)) { diff --git a/src/redis.c b/src/redis.c index 030cfbb4..08a06e4f 100644 --- a/src/redis.c +++ b/src/redis.c @@ -2699,6 +2699,7 @@ sds genRedisInfoString(char *section) { char hmem[64]; char peak_hmem[64]; size_t zmalloc_used = zmalloc_used_memory(); + char *evict_policy = maxmemoryToString(); /* Peak memory is updated from time to time by serverCron() so it * may happen that the instantaneous value is slightly bigger than @@ -2719,7 +2720,8 @@ sds genRedisInfoString(char *section) { "used_memory_peak_human:%s\r\n" "used_memory_lua:%lld\r\n" "mem_fragmentation_ratio:%.2f\r\n" - "mem_allocator:%s\r\n", + "mem_allocator:%s\r\n" + "maxmemory_policy:%s\r\n", zmalloc_used, hmem, server.resident_set_size, @@ -2727,7 +2729,8 @@ sds genRedisInfoString(char *section) { peak_hmem, ((long long)lua_gc(server.lua,LUA_GCCOUNT,0))*1024LL, zmalloc_get_fragmentation_ratio(server.resident_set_size), - ZMALLOC_LIB + ZMALLOC_LIB, + evict_policy ); } diff --git a/src/redis.h b/src/redis.h index 88cbe2f9..53a93f00 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1255,6 +1255,7 @@ void closeListeningSockets(int unlink_unix_socket); void updateCachedTime(void); void resetServerStats(void); unsigned int getLRUClock(void); +char *maxmemoryToString(void); /* Set data type */ robj *setTypeCreate(robj *value); From ec5a0c548b0afbb1bd584b5761bf740460fd20a2 Mon Sep 17 00:00:00 2001 From: Matt Stancliff Date: Tue, 17 Jun 2014 23:05:30 -0400 Subject: [PATCH 2/2] Add cached total system memory to INFO output There is no standard cross-platform way of obtaining system memory info, but I found a useful function convering all common platforms. I removed support for uncommon Redis platforms (windows, AIX) and left others intact. For more info, see: http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system The system memory info is cached on startup, but some systems may be able to change the amount of memory visible to Redis at runtime if Redis is deployed in a VM or container. Also see #1820 --- src/redis.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/redis.h | 2 ++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/redis.c b/src/redis.c index 08a06e4f..be69224c 100644 --- a/src/redis.c +++ b/src/redis.c @@ -53,6 +53,7 @@ #include #include #include +#include /* Our shared "common" objects */ @@ -288,6 +289,7 @@ struct redisCommand redisCommandTable[] = { }; struct evictionPoolEntry *evictionPoolAlloc(void); +static size_t getMemorySize(void); /*============================ Utility functions ============================ */ @@ -1759,6 +1761,7 @@ void initServer(void) { server.clients_waiting_acks = listCreate(); server.get_ack_from_slaves = 0; server.clients_paused = 0; + server.system_memory_size = getMemorySize(); createSharedObjects(); adjustOpenFilesLimit(); @@ -2479,7 +2482,6 @@ void timeCommand(redisClient *c) { addReplyBulkLongLong(c,tv.tv_usec); } - /* Helper function for addReplyCommand() to output flags. */ int addReplyCommandFlag(redisClient *c, struct redisCommand *cmd, int f, char *reply) { if (cmd->flags & f) { @@ -2570,6 +2572,54 @@ void commandCommand(redisClient *c) { } } +/** + * Returns the size of physical memory (RAM) in bytes. + * It looks ugly, but this is the cleanest way to achive cross platform results. + * Cleaned up from: + * http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system + */ +size_t getMemorySize() { +#if defined(__unix__) || defined(__unix) || defined(unix) || \ + (defined(__APPLE__) && defined(__MACH__)) +#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64)) + int mib[2]; + mib[0] = CTL_HW; +#if defined(HW_MEMSIZE) + mib[1] = HW_MEMSIZE; /* OSX. --------------------- */ +#elif defined(HW_PHYSMEM64) + mib[1] = HW_PHYSMEM64; /* NetBSD, OpenBSD. --------- */ +#endif + int64_t size = 0; /* 64-bit */ + size_t len = sizeof(size); + if (sysctl( mib, 2, &size, &len, NULL, 0) == 0) + return (size_t)size; + return 0L; /* Failed? */ + +#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) + /* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */ + return (size_t)sysconf(_SC_PHYS_PAGES) * (size_t)sysconf(_SC_PAGESIZE); + +#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM)) + /* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */ + int mib[2]; + mib[0] = CTL_HW; +#if defined(HW_REALMEM) + mib[1] = HW_REALMEM; /* FreeBSD. ----------------- */ +#elif defined(HW_PYSMEM) + mib[1] = HW_PHYSMEM; /* Others. ------------------ */ +#endif + unsigned int size = 0; /* 32-bit */ + size_t len = sizeof(size); + if (sysctl(mib, 2, &size, &len, NULL, 0) == 0) + return (size_t)size; + return 0L; /* Failed? */ +#endif /* sysctl and sysconf variants */ + +#else + return 0L; /* Unknown OS. */ +#endif +} + /* Convert an amount of bytes into a human readable string in the form * of 100B, 2G, 100M, 4K, and so forth. */ void bytesToHuman(char *s, unsigned long long n) { @@ -2698,7 +2748,9 @@ sds genRedisInfoString(char *section) { if (allsections || defsections || !strcasecmp(section,"memory")) { char hmem[64]; char peak_hmem[64]; + char total_system_hmem[64]; size_t zmalloc_used = zmalloc_used_memory(); + size_t total_system_mem = server.system_memory_size; char *evict_policy = maxmemoryToString(); /* Peak memory is updated from time to time by serverCron() so it @@ -2710,6 +2762,8 @@ sds genRedisInfoString(char *section) { bytesToHuman(hmem,zmalloc_used); bytesToHuman(peak_hmem,server.stat_peak_memory); + bytesToHuman(total_system_hmem,total_system_mem); + if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Memory\r\n" @@ -2718,6 +2772,8 @@ sds genRedisInfoString(char *section) { "used_memory_rss:%zu\r\n" "used_memory_peak:%zu\r\n" "used_memory_peak_human:%s\r\n" + "total_system_memory:%lu\r\n" + "total_system_memory_human:%s\r\n" "used_memory_lua:%lld\r\n" "mem_fragmentation_ratio:%.2f\r\n" "mem_allocator:%s\r\n" @@ -2727,6 +2783,8 @@ sds genRedisInfoString(char *section) { server.resident_set_size, server.stat_peak_memory, peak_hmem, + (unsigned long)total_system_mem, + total_system_hmem, ((long long)lua_gc(server.lua,LUA_GCCOUNT,0))*1024LL, zmalloc_get_fragmentation_ratio(server.resident_set_size), ZMALLOC_LIB, diff --git a/src/redis.h b/src/redis.h index 53a93f00..afed4b88 100644 --- a/src/redis.h +++ b/src/redis.h @@ -908,6 +908,8 @@ struct redisServer { int assert_line; int bug_report_start; /* True if bug report header was already logged. */ int watchdog_period; /* Software watchdog period in ms. 0 = off */ + /* System hardware info */ + size_t system_memory_size; /* Total memory in system as reported by OS */ }; typedef struct pubsubPattern {