|  | #!/bin/bash | 
|  |  | 
|  | # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | # This script creates a CPU set and binds the MySQL process to the | 
|  | # set. It restarts MySQL if specified in the option. This script needs | 
|  | # to be run with "sudo". | 
|  |  | 
|  | set -e # Exit if any function returns a non-zero value. | 
|  | set -o nounset # Exit if any variable is used unset. | 
|  |  | 
|  | MYSQL_PATH='/etc/init.d/mysql.server' | 
|  | MYSQL_PID_PATH='/var/lib/mysql/atlantis1.mtv.corp.google.com.pid' | 
|  | MYSQL_PROC_NAME='mysqld' | 
|  |  | 
|  | # The directory where we mount the cpuset virutal file system to. | 
|  | MOUNT_DIR='/dev/cpuset' | 
|  | # The base cpuset directory for mysql. | 
|  | MYSQL_CPUSET='mysql' | 
|  | # CPUs in MySQL cpuset. E.g. 0-2,7,12-14. | 
|  | MYSQL_DEFAULT_CPUS=10-15 | 
|  |  | 
|  |  | 
|  | # Display usage. | 
|  | function usage() { | 
|  | echo -e "Usage: $0 [-c <CPUs>] [-p <PID>] [-r] [-d]\n" | 
|  | echo -e "Create and bind the MySQL process to a specified CPU set.\n" | 
|  | echo -e "Options:" | 
|  | echo -e "  -c <CPUs>  Specify a list of CPUs to be used. E.g. 0-2,7,12-14" | 
|  | echo -e "             (Default: $MYSQL_DEFAULT_CPUS)." | 
|  | echo -e "  -d         Delete the CPU set. This option kills the current" | 
|  | echo -e "             MySQL process and delete the CPU set. It does not" | 
|  | echo -e "             restart MySQL nor create a new CPU set. (Default:" | 
|  | echo -e "             disabled)." | 
|  | echo -e "  -p <PID>   Bind <PID> to the cpuset (Default: the script searches" | 
|  | echo -e "             for the MySQL PID automatically)." | 
|  | echo -e "  -r         Restart MySQL (Default: disabled)." | 
|  | echo -e "  -h         Display this usage information." | 
|  | echo -e "\n" | 
|  | } | 
|  |  | 
|  | function print_info() { | 
|  | msg=$1 | 
|  | echo "INFO:  "$msg | 
|  | } | 
|  |  | 
|  | function print_error() { | 
|  | msg=$1 | 
|  | echo "ERROR: "$msg | 
|  | } | 
|  |  | 
|  | # Run and print out the command if the silent flag is not set (the default). | 
|  | # Usage: run_cmd <cmd> [slient] | 
|  | function run_cmd() { | 
|  | cmd="" | 
|  | slient=0 | 
|  |  | 
|  | if [ $# -gt 0 ]; then | 
|  | cmd=$1 | 
|  | else | 
|  | print_error "Empty command!" | 
|  | return 1 | 
|  | fi | 
|  |  | 
|  | if [ $# -gt 1 ]; then | 
|  | silent=$2 | 
|  | fi | 
|  |  | 
|  | if [ $slient -eq 0 ]; then | 
|  | print_info "Running \"${1}\"" | 
|  | fi | 
|  |  | 
|  | # Print an error message if the command failed. | 
|  | eval "$1" || { print_error "Failed to execute \"${cmd}\""; return 1; } | 
|  | } | 
|  |  | 
|  | # Get the PID of the MySQL. | 
|  | function get_mysql_pid() { | 
|  | local pid="" | 
|  |  | 
|  | if [ $# -gt 0 ] && [ ! -z "$1" ]; then | 
|  | # Use user-provided PID. | 
|  | pid=$1 | 
|  | elif [ ! -z ${MYSQL_PID_PATH} -a -f ${MYSQL_PID_PATH} ]; then | 
|  | # Get PID from MySQL PID file if it is set. | 
|  | print_info "Getting MySQL PID from ${MYSQL_PID_PATH}..." | 
|  | pid=$(cat $MYSQL_PID_PATH) || \ | 
|  | { print_error "No MySQL process found."; return 1; } | 
|  | else | 
|  | # Get PID of process named mysqld. | 
|  | print_info "Searching for MySQL PID..." | 
|  | # Ignore the return code to print out an error message. | 
|  | pid=$(pidof $MYSQL_PROC_NAME) || \ | 
|  | { print_error "No MySQL process found."; return 1; } | 
|  | fi | 
|  |  | 
|  | # Test if the PID is an integer | 
|  | if [[ $pid != [0-9]* ]]; then | 
|  | print_error "No MySQL process found." | 
|  | return 1 | 
|  | fi | 
|  |  | 
|  | # Check if the PID is a running process. | 
|  | if [ ! -d "/proc/${pid}" ]; then | 
|  | print_error "No running MySQL process is found." | 
|  | return 1 | 
|  | fi | 
|  |  | 
|  | _RET="$pid" | 
|  | print_info "MySQL PID is ${pid}." | 
|  | } | 
|  |  | 
|  | # Mount the cpuset virtual file system. | 
|  | function mount_cpuset() { | 
|  | if (mount | grep "on ${MOUNT_DIR} type" > /dev/null) | 
|  | then | 
|  | print_info "${MOUNT_DIR} already mounted." | 
|  | else | 
|  | print_info "Mounting cpuset to $MOUNT_DIR." | 
|  | run_cmd "mkdir -p ${MOUNT_DIR}" | 
|  | run_cmd "mount -t cpuset none ${MOUNT_DIR}" | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | function clean_all() { | 
|  | local delete_msg="No" | 
|  | print_info "Will Delete existing CPU set..." | 
|  | echo -ne "WARNING: This operation will kill all running " | 
|  | echo "processes in the CPU set." | 
|  | echo -ne "Are you sure you want to proceed " | 
|  | echo -ne "(type \"yes\" or \"Yes\" to proceed)? " | 
|  | read delete_msg | 
|  |  | 
|  | mount_cpuset | 
|  |  | 
|  | local proc_list="" | 
|  | local proc="" | 
|  |  | 
|  | if [ "$delete_msg" = "yes" -o "$delete_msg" = "Yes" ]; then | 
|  | if [ -d "${MOUNT_DIR}/${MYSQL_CPUSET}" ]; then | 
|  | proc_list=$(cat ${MOUNT_DIR}/${MYSQL_CPUSET}/cgroup.procs) | 
|  | for proc in $proc_list; do | 
|  | run_cmd "kill -9 ${proc}" | 
|  | done | 
|  | # Remove the CPU set directory. | 
|  | run_cmd "rmdir ${MOUNT_DIR}/${MYSQL_CPUSET}" | 
|  | # Unmount the cpuset virtual file system. | 
|  | run_cmd "umount ${MOUNT_DIR}" | 
|  | else | 
|  | print_info "The CPU set does not exist." | 
|  | return 1 | 
|  | fi | 
|  | print_info "Done!" | 
|  | else | 
|  | # User does not wish to continue. | 
|  | print_info "Aborting program." | 
|  | fi | 
|  | } | 
|  |  | 
|  |  | 
|  | function main() { | 
|  |  | 
|  | local MYSQL_CPUS=$MYSQL_DEFAULT_CPUS | 
|  | local RESTART_MYSQL_FLAG=0 | 
|  | local DELETE_CPUSET_FLAG=0 | 
|  | local MYSQL_PID="" | 
|  |  | 
|  | # Parse command-line arguments. | 
|  | while getopts ":c:dhp:r" opt; do | 
|  | case $opt in | 
|  | c) | 
|  | MYSQL_CPUS=$OPTARG | 
|  | ;; | 
|  | d) | 
|  | DELETE_CPUSET_FLAG=1 | 
|  | ;; | 
|  | h) | 
|  | usage | 
|  | return 0 | 
|  | ;; | 
|  | p) | 
|  | MYSQL_PID=$OPTARG | 
|  | ;; | 
|  | r) | 
|  | RESTART_MYSQL_FLAG=1 | 
|  | ;; | 
|  | \?) | 
|  | echo "Invalid option: -$OPTARG" >&2 | 
|  | usage | 
|  | return 1 | 
|  | ;; | 
|  | :) | 
|  | echo "Option -$OPTARG requires an argument." >&2 | 
|  | usage | 
|  | return 1 | 
|  | ;; | 
|  | esac | 
|  | done | 
|  |  | 
|  |  | 
|  | # Clean up and exit if the flag is set. | 
|  | if [ $DELETE_CPUSET_FLAG -eq 1 ]; then | 
|  | clean_all | 
|  | return 0 | 
|  | fi | 
|  |  | 
|  | # Restart MySQL. | 
|  | if [ $RESTART_MYSQL_FLAG -eq 1 ]; then | 
|  | print_info "Restarting MySQL..." | 
|  | $MYSQL_PATH restart | 
|  | fi | 
|  |  | 
|  |  | 
|  | # Get PID of MySQL. | 
|  | get_mysql_pid "$MYSQL_PID" | 
|  | MYSQL_PID=$_RET | 
|  |  | 
|  | mount_cpuset | 
|  |  | 
|  | # Make directory for MySql. | 
|  | print_info "Making a cpuset for MySQL..." | 
|  | run_cmd "mkdir -p ${MOUNT_DIR}/${MYSQL_CPUSET}" | 
|  |  | 
|  | # Change working directory. | 
|  | run_cmd "cd ${MOUNT_DIR}/${MYSQL_CPUSET}" | 
|  |  | 
|  | # Update the CPUs to use in the CPU set. Note that we use /bin/echo | 
|  | # explicitly (instead of "echo") because it displays write errors. | 
|  | print_info "Updating CPUs in the cpuset..." | 
|  | run_cmd "bash -c \"/bin/echo ${MYSQL_CPUS} > cpus\"" | 
|  |  | 
|  | # Attach/Rebind MySQL process to the cpuset. Note that this command | 
|  | # can only attach one PID at a time. This needs to be run every time | 
|  | # after the CPU set is modified. | 
|  | print_info "Bind MySQL process to the cpuset..." | 
|  | run_cmd "bash -c \"/bin/echo ${MYSQL_PID} > tasks\"" | 
|  |  | 
|  | print_info "Done!" | 
|  | } | 
|  |  | 
|  | main "$@" |