static int parse_args(struct config *cfg, char **host, char **port, int argc, char **argv) { char c, *host_str; memset(cfg, 0, sizeof(struct config)); cfg->threads = 2; cfg->connections = 10; cfg->duration = 10; cfg->timeout = SOCKET_TIMEOUT_MS; while ((c = getopt_long(argc, argv, "t:c:d:T:Lrv?", longopts, NULL)) != -1) { switch (c) { case 't': if (scan_metric(optarg, &cfg->threads)) return -1; break; case 'c': if (scan_metric(optarg, &cfg->connections)) return -1; break; case 'd': if (scan_time(optarg, &cfg->duration)) return -1; break; case 'L': cfg->latency = true; break; case 'T': if (scan_time(optarg, &cfg->timeout)) return -1; cfg->timeout *= 1000; break; case 'v': printf("wrk-nonsense %s [%s] ", VERSION, aeGetApiName()); printf("Copyright (C) 2012 Will Glozer (hackt up by Forrest L Norvell)\n"); break; case 'r': fprintf(stderr, "wrk 2.0.0+ uses -d instead of -r\n"); case 'h': case '?': case ':': default: return -1; } } if (!cfg->threads || !cfg->duration) return -1; if (!cfg->connections || cfg->connections < cfg->threads) { fprintf(stderr, "number of connections must be >= threads\n"); return -1; } if (argc > 1 && optind < argc) { host_str = strdup(argv[optind]); *host = strsep(&host_str, ":"); *port = host_str; } return 0; }
/* Create the string returned by the INFO command. This is decoupled * by the INFO command itself as we need to report the same information * on memory corruption problems. */ sds genVireInfoString(char *section) { sds info = sdsempty(); time_t uptime = time(NULL)-server.starttime; int j, numcommands; struct rusage self_ru; unsigned long lol, bib; int allsections = 0, defsections = 0; int sections = 0; long long keys_all, vkeys_all, avg_ttl_all; int nexit = 0; keys_all = vkeys_all = avg_ttl_all = 0; if (section == NULL) section = "default"; allsections = strcasecmp(section,"all") == 0; defsections = strcasecmp(section,"default") == 0; getrusage(RUSAGE_SELF, &self_ru); /* Server */ if (allsections || defsections || !strcasecmp(section,"server")) { static int call_uname = 1; static struct utsname name; char *mode; mode = "standalone"; if (sections++) info = sdscat(info,"\r\n"); if (call_uname) { /* Uname can be slow and is always the same output. Cache it. */ uname(&name); call_uname = 0; } info = sdscatprintf(info, "# Server\r\n" "vire_version:%s\r\n" "vire_mode:%s\r\n" "os:%s %s %s\r\n" "arch_bits:%d\r\n" "multiplexing_api:%s\r\n" "gcc_version:%d.%d.%d\r\n" "process_id:%ld\r\n" "run_id:%s\r\n" "tcp_port:%d\r\n" "uptime_in_seconds:%jd\r\n" "uptime_in_days:%jd\r\n" "hz:%d\r\n" "executable:%s\r\n" "config_file:%s\r\n", VR_VERSION_STRING, mode, name.sysname, name.release, name.machine, server.arch_bits, aeGetApiName(), #ifdef __GNUC__ __GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__, #else 0,0,0, #endif (long) getpid(), server.runid, server.port, (intmax_t)uptime, (intmax_t)(uptime/(3600*24)), server.hz, server.executable ? server.executable : "", server.configfile ? server.configfile : ""); } /* Memory */ if (allsections || defsections || !strcasecmp(section,"memory")) { char hmem[64]; char peak_hmem[64]; char total_system_hmem[64]; char used_memory_lua_hmem[64]; char used_memory_rss_hmem[64]; char maxmemory_hmem[64]; size_t vr_used_memory = vr_alloc_used_memory(); size_t total_system_mem = server.system_memory_size; /* Peak memory is updated from time to time by serverCron() so it * may happen that the instantaneous value is slightly bigger than * the peak value. This may confuse users, so we update the peak * if found smaller than the current memory usage. */ if (vr_used_memory > server.stat_peak_memory) server.stat_peak_memory = vr_used_memory; bytesToHuman(hmem,vr_used_memory); bytesToHuman(peak_hmem,server.stat_peak_memory); bytesToHuman(total_system_hmem,total_system_mem); bytesToHuman(maxmemory_hmem,server.maxmemory); if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Memory\r\n" "used_memory:%zu\r\n" "used_memory_human:%s\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" "maxmemory:%lld\r\n" "maxmemory_human:%s\r\n" "mem_allocator:%s\r\n", vr_used_memory, hmem, server.stat_peak_memory, peak_hmem, (unsigned long)total_system_mem, total_system_hmem, server.maxmemory, maxmemory_hmem, VR_MALLOC_LIB ); } /* Stats */ if (allsections || defsections || !strcasecmp(section,"stats")) { uint32_t idx; vr_worker *worker; vr_stats *stats; long long stat_numconnections=0, stat_numcommands=0; long long stat_net_input_bytes=0, stat_net_output_bytes=0; long long stat_rejected_conn=0; long long stat_expiredkeys=0; long long stat_keyspace_hits=0, stat_keyspace_misses=0; for (idx = 0; idx < array_n(&workers); idx ++) { worker = array_get(&workers, idx); stats = worker->vel.stats; #if (defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)) && defined(STATS_ATOMIC_FIRST) stat_numcommands += update_stats_add(stats, numcommands, 0); stat_numconnections += update_stats_add(stats, numconnections, 0); stat_expiredkeys += update_stats_add(stats, expiredkeys, 0); stat_net_input_bytes += update_stats_add(stats, net_input_bytes, 0); stat_net_output_bytes += update_stats_add(stats, net_output_bytes, 0); stat_keyspace_hits += update_stats_add(stats, keyspace_hits, 0); stat_keyspace_misses += update_stats_add(stats, keyspace_misses, 0); #else pthread_spin_lock(&stats->statslock); stat_numcommands += stats->numcommands; stat_numconnections += stats->numconnections; stat_expiredkeys += stats->expiredkeys; stat_net_input_bytes += stats->net_input_bytes; stat_net_output_bytes += stats->net_output_bytes; stat_keyspace_hits += stats->keyspace_hits; stat_keyspace_misses += stats->keyspace_misses; pthread_spin_unlock(&stats->statslock); #endif } #if (defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)) && defined(STATS_ATOMIC_FIRST) stat_rejected_conn += update_stats_add(master.vel.stats, rejected_conn, 0); #else pthread_spin_lock(&master.vel.stats->statslock); stat_rejected_conn = master.vel.stats->rejected_conn; pthread_spin_unlock(&master.vel.stats->statslock); #endif if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Stats\r\n" "total_connections_received:%lld\r\n" "total_commands_processed:%lld\r\n" "total_net_input_bytes:%lld\r\n" "total_net_output_bytes:%lld\r\n" "rejected_connections:%lld\r\n" "expired_keys:%lld\r\n" "keyspace_hits:%lld\r\n" "keyspace_misses:%lld\r\n", stat_numconnections, stat_numcommands, stat_net_input_bytes, stat_net_output_bytes, stat_rejected_conn, stat_expiredkeys, stat_keyspace_hits, stat_keyspace_misses); } /* CPU */ if (allsections || defsections || !strcasecmp(section,"cpu")) { if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# CPU\r\n" "used_cpu_sys:%.2f\r\n" "used_cpu_user:%.2f\r\n", (float)self_ru.ru_stime.tv_sec+(float)self_ru.ru_stime.tv_usec/1000000, (float)self_ru.ru_utime.tv_sec+(float)self_ru.ru_utime.tv_usec/1000000); } /* Internal */ if (allsections || !strcasecmp(section,"internal")) { redisDb *db; long long keys, vkeys, avg_ttl; if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Internal\r\n"); for (j = 0; j < server.dbnum; j++) { db = array_get(&server.dbs, j); pthread_rwlock_rdlock(&db->rwl); keys = dictSize(db->dict); vkeys = dictSize(db->expires); avg_ttl = db->avg_ttl; pthread_rwlock_unlock(&db->rwl); if (keys || vkeys) { info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld,avg_ttl=%lld\r\n", j, keys, vkeys, db->avg_ttl); } keys_all += keys; vkeys_all += vkeys; avg_ttl_all += avg_ttl; if (avg_ttl > 0) nexit ++; } } /* Key space */ if (allsections || defsections || !strcasecmp(section,"keyspace")) { redisDb *db; if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Keyspace\r\n"); if (keys_all == 0) { for (j = 0; j < server.dbnum; j++) { db = array_get(&server.dbs, j); pthread_rwlock_rdlock(&db->rwl); keys_all += dictSize(db->dict); vkeys_all += dictSize(db->expires); avg_ttl_all += db->avg_ttl; if (db->avg_ttl > 0) nexit ++; pthread_rwlock_unlock(&db->rwl); } } if (keys_all || vkeys_all) { info = sdscatprintf(info, "keys=%lld,expires=%lld,avg_ttl=%lld\r\n", keys_all, vkeys_all, nexit > 0 ? (avg_ttl_all/nexit) : 0); } } return info; }