Skip to content

Instantly share code, notes, and snippets.

@mrqwer88
Created October 3, 2017 14:50
Show Gist options
  • Save mrqwer88/1b5c42dc526e708d7111a1f3ce0c9633 to your computer and use it in GitHub Desktop.
Save mrqwer88/1b5c42dc526e708d7111a1f3ce0c9633 to your computer and use it in GitHub Desktop.
ksmctl from rhel ksm packages with added default params support
# The maximum number of unswappable kernel pages
# which may be allocated by ksm (0 for unlimited)
# If unset, defaults to half of total memory
# KSM_MAX_KERNEL_PAGES=
# KSM_SLEEP_MSECS=20
# KSM_PAGES_TO_SCAN=100
# KSM_MERGE_ACROSS_NODES=1
# KSM_MAX_PAGE_SHARING=256
# KSM_USE_ZERO_PAGES=0
/* Start/stop KSM, for systemd.
* Copyright (C) 2009, 2011 Red Hat, Inc.
* Written by Paolo Bonzini <[email protected]>.
* Based on the original sysvinit script by Dan Kenigsberg <[email protected]>
* This file is distributed under the GNU General Public License, version 2
* or later. */
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define KSM_MAX_KERNEL_PAGES_FILE "/sys/kernel/mm/ksm/max_kernel_pages"
#define KSM_RUN_FILE "/sys/kernel/mm/ksm/run"
#define KSM_PAGES_TO_SCAN_FILE "/sys/kernel/mm/ksm/pages_to_scan"
#define KSM_SLEEP_MSECS_FILE "/sys/kernel/mm/ksm/sleep_millisecs"
#define KSM_MERGE_ACROSS_NODES_FILE "/sys/kernel/mm/ksm/merge_across_nodes"
#define KSM_MAX_PAGE_SHARING_FILE "/sys/kernel/mm/ksm/max_page_sharing"
#define KSM_USE_ZERO_PAGES_FILE "/sys/kernel/mm/ksm/use_zero_pages"
char *program_name;
int usage(void)
{
fprintf(stderr, "Usage: %s {start|stop}\n", program_name);
return 1;
}
int write_value(uint64_t value, char *filename)
{
FILE *fp;
if (!(fp = fopen(filename, "w")) ||
fprintf(fp, "%llu\n", (unsigned long long) value) == EOF ||
fflush(fp) == EOF ||
fclose(fp) == EOF)
return 1;
return 0;
}
uint64_t ksm_max_kernel_pages()
{
char *var = getenv("KSM_MAX_KERNEL_PAGES");
char *endptr;
uint64_t value;
if (var && *var) {
value = strtoll(var, &endptr, 0);
if (value < LLONG_MAX && !*endptr)
return value;
}
/* Unless KSM_MAX_KERNEL_PAGES is set, let KSM munch up to half of
* total memory. */
return sysconf(_SC_PHYS_PAGES) / 2;
}
uint64_t ksm_by_unsigned_int(char *env_name, uint64_t default_value){
char *var = getenv(env_name);
char *endptr;
uint64_t value;
if (var && *var) {
value = strtoll(var, &endptr, 0);
if (value < UINT_MAX && !*endptr)
return value;
}
return default_value;
}
uint64_t ksm_by_int(char *env_name, uint64_t default_value){
char *var = getenv(env_name);
char *endptr;
uint64_t value;
if (var && *var) {
value = strtoll(var, &endptr, 0);
if (value < INT_MAX && !*endptr)
return value;
}
return default_value;
}
int start(void)
{
if (access(KSM_MAX_KERNEL_PAGES_FILE, R_OK) >= 0)
write_value(ksm_max_kernel_pages(), KSM_MAX_KERNEL_PAGES_FILE);
/* Milliseconds ksmd should sleep between batches
* static unsigned int ksm_thread_sleep_millisecs = 20;
*/
if (getenv("KSM_SLEEP_MSECS") && access(KSM_SLEEP_MSECS_FILE, R_OK) >= 0)
write_value(ksm_by_unsigned_int("KSM_SLEEP_MSECS", 20), KSM_SLEEP_MSECS_FILE);
/* Number of pages ksmd should scan in one batch
* static unsigned int ksm_thread_pages_to_scan = 100;
*/
if (getenv("KSM_PAGES_TO_SCAN") && access(KSM_PAGES_TO_SCAN_FILE, R_OK) >= 0)
write_value(ksm_by_unsigned_int("KSM_PAGES_TO_SCAN", 100), KSM_PAGES_TO_SCAN_FILE);
/* Zeroed when merging across nodes is not allowed
* static unsigned int ksm_merge_across_nodes = 1;
*/
if (getenv("KSM_MERGE_ACROSS_NODES") && access(KSM_PAGES_TO_SCAN_FILE, R_OK) >= 0)
write_value(ksm_by_unsigned_int("KSM_MERGE_ACROSS_NODES", 1), KSM_MERGE_ACROSS_NODES_FILE);
/* Maximum number of page slots sharing a stable node
* static int ksm_max_page_sharing = 256;
*/
if (getenv("KSM_MAX_PAGE_SHARING") && access(KSM_PAGES_TO_SCAN_FILE, R_OK) >= 0)
write_value(ksm_by_int("KSM_MAX_PAGE_SHARING", 256), KSM_MAX_PAGE_SHARING_FILE);
/* Whether to merge empty (zeroed) pages with actual zero pages
* Default to false for backwards compatibility
* ksm_use_zero_pages = false;
*/
if (getenv("KSM_USE_ZERO_PAGES") && access(KSM_PAGES_TO_SCAN_FILE, R_OK) >= 0)
write_value(ksm_by_unsigned_int("KSM_USE_ZERO_PAGES", 0), KSM_USE_ZERO_PAGES_FILE);
return write_value(1, KSM_RUN_FILE);
}
int stop(void)
{
return write_value(0, KSM_RUN_FILE);
}
int main(int argc, char **argv)
{
program_name = argv[0];
if (argc < 2) {
return usage();
} else if (!strcmp(argv[1], "start")) {
return start();
} else if (!strcmp(argv[1], "stop")) {
return stop();
} else {
return usage();
}
}
@mrqwer88
Copy link
Author

mrqwer88 commented Oct 3, 2017

Comments and default value were gotten from ./mm/kms.c file from 4.13 kernel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment