diff --git a/master.c b/master.c index 681b5856..2416b4f4 100644 --- a/master.c +++ b/master.c @@ -1432,6 +1432,14 @@ healthy: } #endif +#ifdef __linux__ +#ifdef MADV_MERGEABLE + if (uwsgi.linux_ksm > 0 && (uwsgi.master_cycles % uwsgi.linux_ksm) == 0) { + uwsgi_linux_ksm_map(); + } +#endif +#endif + #ifdef UWSGI_UDP // check for cluster nodes master_check_cluster_nodes(); diff --git a/utils.c b/utils.c index 4ca2d9d9..a1194bc9 100644 --- a/utils.c +++ b/utils.c @@ -717,8 +717,96 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) { uwsgi.loyal = 1; } +#ifdef __linux__ +#ifdef MADV_MERGEABLE + // run the ksm mapper + if (uwsgi.linux_ksm > 0 && (uwsgi.workers[uwsgi.mywid].requests % uwsgi.linux_ksm) == 0) { + uwsgi_linux_ksm_map(); + } +#endif +#endif + } +#ifdef __linux__ +#ifdef MADV_MERGEABLE + +unsigned long long *ksm_mappings_last = NULL; +int ksm_mappings_last_lines = 0; +unsigned long long *ksm_mappings_current = NULL; +int ksm_mappings_current_lines = 0; + +void uwsgi_linux_ksm_map(void) { + + char map_line_buf[1024]; + unsigned long long start, end; + int dirty = 0; + int i; + int errors = 0; + unsigned long long *tmp_ptr; + + ksm_mappings_current = NULL; + ksm_mappings_current_lines = 0; + + FILE *process_maps = fopen("/proc/self/maps", "r"); + + if (process_maps) { + while( fgets(map_line_buf, 1024, process_maps)) { + if (fscanf(process_maps, "%llx-%llx %*s", &start, &end) == 2) { + ksm_mappings_current_lines+=2; + tmp_ptr = ksm_mappings_current; + ksm_mappings_current = realloc(ksm_mappings_current, sizeof(unsigned long long) * ksm_mappings_current_lines); + if (!ksm_mappings_current) { + uwsgi_error("[uwsgi-KSM] /proc/self/maps realloc()"); + fclose(process_maps); + if (tmp_ptr) { + free(tmp_ptr); + } + return; + } + ksm_mappings_current[ksm_mappings_current_lines-2] = start; + ksm_mappings_current[ksm_mappings_current_lines-1] = end; + } + } + fclose(process_maps); + + if (ksm_mappings_last == NULL || ksm_mappings_last_lines == 0 || ksm_mappings_last_lines != ksm_mappings_current_lines) { + dirty = 1; + } + else { + for(i=0;i= ksm_mappings_current_lines) { + uwsgi_error("[uwsgi-KSM] unable to share pages"); + } + } + } +} +#endif +#endif + void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id, struct uwsgi_socket *uwsgi_sock) { wsgi_req->poll.events = POLLIN; diff --git a/uwsgi.c b/uwsgi.c index c64f2aed..3f16993b 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -176,6 +176,11 @@ static struct option long_base_options[] = { {"reload-on-rss", required_argument, 0, LONG_ARGS_RELOAD_ON_RSS}, {"evil-reload-on-as", required_argument, 0, LONG_ARGS_EVIL_RELOAD_ON_AS}, {"evil-reload-on-rss", required_argument, 0, LONG_ARGS_EVIL_RELOAD_ON_RSS}, +#ifdef __linux__ +#ifdef MADV_MERGEABLE + {"ksm", optional_argument, 0, LONG_ARGS_KSM}, +#endif +#endif {"touch-reload", required_argument, 0, LONG_ARGS_TOUCH_RELOAD}, {"propagate-touch", no_argument, &uwsgi.propagate_touch, 1}, {"limit-post", required_argument, 0, LONG_ARGS_LIMIT_POST}, @@ -2442,6 +2447,7 @@ skipzero: } + if (!uwsgi.master_process && uwsgi.numproc == 0) { exit(0); } @@ -2449,6 +2455,16 @@ skipzero: uwsgi_log("*** uWSGI is running in multiple interpreter mode ***\n"); } +#ifdef __linux__ +#ifdef MADV_MERGEABLE + if (uwsgi.linux_ksm > 0) { + uwsgi_log("[uwsgi-KSM] enabled with frequency: %d\n", uwsgi.linux_ksm); + } +#endif +#endif + + + if (uwsgi.master_process) { if (uwsgi.is_a_reload) { uwsgi_log("gracefully (RE)spawned uWSGI master process (pid: %d)\n", uwsgi.mypid); @@ -2541,6 +2557,8 @@ skipzero: } } + + if (getpid() == masterpid && uwsgi.master_process == 1) { #ifdef UWSGI_AS_SHARED_LIBRARY int ml_ret = master_loop(uwsgi.argv, uwsgi.environ); @@ -3415,6 +3433,16 @@ static int manage_base_opt(int i, char *optarg) { case LONG_ARGS_LIMIT_POST: uwsgi.limit_post = (int) strtol(optarg, NULL, 10); return 1; +#ifdef __linux__ +#ifdef MADV_MERGEABLE + case LONG_ARGS_KSM: + uwsgi.linux_ksm = 1; + if (optarg) { + uwsgi.linux_ksm = atoi(optarg); + } + return 1; +#endif +#endif case LONG_ARGS_RELOAD_ON_AS: uwsgi.force_get_memusage = 1; uwsgi.reload_on_as = (strtoul(optarg, NULL, 10)) * 1024 * 1024; diff --git a/uwsgi.h b/uwsgi.h index f3176f64..a5149cdc 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -540,6 +540,7 @@ struct uwsgi_opt { #define LONG_ARGS_PAUSE 17161 #define LONG_ARGS_SIGNAL_BUFSIZE 17162 #define LONG_ARGS_SIGNAL 17163 +#define LONG_ARGS_KSM 17164 #define UWSGI_OK 0 @@ -1525,6 +1526,12 @@ struct uwsgi_server { // subscription client struct uwsgi_string_list *subscriptions; +#ifdef __linux__ +#ifdef MADV_MERGEABLE + int linux_ksm; +#endif +#endif + }; struct uwsgi_rpc { @@ -2459,6 +2466,12 @@ void uwsgi_add_app(int, uint8_t, char *, int); int uwsgi_signal_send(int, uint8_t); int uwsgi_remote_signal_send(char *, uint8_t); +#ifdef __linux__ +#ifdef MADV_MERGEABLE +void uwsgi_linux_ksm_map(void); +#endif +#endif + #ifdef UWSGI_CAP void uwsgi_build_cap(char *); #endif