4 ## Copyright (c) 2010-2017 Intel Corporation
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
10 ## http://www.apache.org/licenses/LICENSE-2.0
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
20 from os import fork, _exit
21 from subprocess import check_output
23 from time import sleep
27 # This script starts qemu with the CPU layout specified by the cores
28 # array below. Each element in the array represents a core. To enable
29 # hyper-threading (i.e. two logical cores per core), each element in
30 # the array should be an array of length two. The values stored inside
31 # the array define to which host cores the guest cores should be
32 # affinitized. All arguments of this script are passed to qemu
33 # directly. Porting an existing qemu command line setup to make use of
34 # this script requires removing the -smp parameters and -qmp
35 # parameters if those were used. These are built by the script based
38 # After successfully starting qemu, this script will connect through
39 # QMP and affinitize all cores within the VM to match cores on the
42 execfile("./vm-cores.py")
44 def build_mask(cores):
52 n_threads = len(cores[0]);
54 mask = str(hex((build_mask(cores))))
56 smp_str = str(n_cores*n_threads)
57 smp_str += ",cores=" + str(n_cores)
58 smp_str += ",sockets=1"
59 smp_str += ",threads=" + str(n_threads)
62 qmp_sock = check_output(["mktemp", "--tmpdir", "qmp-sock-XXXX"]).strip()
64 qmp_sock = "/tmp/qmp-sock"
67 qemu_cmdline += "taskset " + mask + " qemu-system-x86_64 -smp " + smp_str
68 qemu_cmdline += " -qmp unix:" + qmp_sock + ",server,nowait"
69 qemu_cmdline += " -daemonize"
71 for a in sys.argv[1:]:
72 qemu_cmdline += " " + a
77 sys.exit("Failed to fork: " + e.strerror)
80 # In the parent process
81 ret = system(qemu_cmdline)
83 sys.exit("Failed to run QEMU: exit status " + str(ret) + ". Command line was:\n" + qemu_cmdline)
87 # In the child process: use _exit to terminate
89 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
94 print "Connected to QMP"
99 print "Failed to connect to QMP, attempt " + str(retry)
101 print "Failed to connect to QMP"
104 # skip info about protocol
106 # need to run qmp_capabilities before next command works
107 s.send("{\"execute\" : \"qmp_capabilities\" }")
109 # Get the PID for each guest core
110 s.send("{\"execute\" : \"query-cpus\"}")
112 a = json.loads(dat)["return"];
114 if (len(a) != n_cores*n_threads):
115 print "Configuration mismatch: " + str(len(a)) + " vCPU reported by QMP, instead of expected " + str(n_cores*n_threads)
117 print "QMP reported " + str(len(a)) + " vCPU, as expected"
122 cm = str(hex(1 << cores[idx][0]))
123 pid = str(core["thread_id"])
124 system("taskset -p " + cm + " " + pid + " > /dev/null")
126 elif (n_threads == 2):
130 cm = str(hex(1 << cores[idx][prev]))
131 pid = str(core["thread_id"])
132 system("taskset -p " + cm + " " + pid + " > /dev/null")
138 print "Not implemented yet: more than 2 threads per core"
141 print "Core affinitization completed"