lin
2025-08-14 dae8bad597b6607a449b32bf76c523423f7720ed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#!/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 "$@"