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 0f0bc56c..732db76b 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,10 @@ 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 * may happen that the instantaneous value is slightly bigger than @@ -2709,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" @@ -2717,17 +2772,23 @@ 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", + "mem_allocator:%s\r\n" + "maxmemory_policy:%s\r\n", zmalloc_used, hmem, 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 + ZMALLOC_LIB, + evict_policy ); } diff --git a/src/redis.h b/src/redis.h index 88cbe2f9..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 { @@ -1255,6 +1257,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);