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
|
#!/bin/env python2.7
##
## Copyright (c) 2010-2017 Intel Corporation
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
from os import system
from os import fork, _exit
from subprocess import check_output
import socket
from time import sleep
import json
import sys
# This script starts qemu with the CPU layout specified by the cores
# array below. Each element in the array represents a core. To enable
# hyper-threading (i.e. two logical cores per core), each element in
# the array should be an array of length two. The values stored inside
# the array define to which host cores the guest cores should be
# affinitized. All arguments of this script are passed to qemu
# directly. Porting an existing qemu command line setup to make use of
# this script requires removing the -smp parameters and -qmp
# parameters if those were used. These are built by the script based
# on the cores array.
# After successfully starting qemu, this script will connect through
# QMP and affinitize all cores within the VM to match cores on the
# host.
execfile("./vm-cores.py")
def build_mask(cores):
ret = 0;
for core in cores:
for thread in core:
ret += 1 << thread;
return ret;
n_cores = len(cores);
n_threads = len(cores[0]);
mask = str(hex((build_mask(cores))))
smp_str = str(n_cores*n_threads)
smp_str += ",cores=" + str(n_cores)
smp_str += ",sockets=1"
smp_str += ",threads=" + str(n_threads)
try:
qmp_sock = check_output(["mktemp", "--tmpdir", "qmp-sock-XXXX"]).strip()
except:
qmp_sock = "/tmp/qmp-sock"
qemu_cmdline = ""
qemu_cmdline += "taskset " + mask + " qemu-system-x86_64 -smp " + smp_str
qemu_cmdline += " -qmp unix:" + qmp_sock + ",server,nowait"
qemu_cmdline += " -daemonize"
for a in sys.argv[1:]:
qemu_cmdline += " " + a
try:
pid = fork()
except OSError, e:
sys.exit("Failed to fork: " + e.strerror)
if (pid != 0):
# In the parent process
ret = system(qemu_cmdline)
if (ret != 0):
sys.exit("Failed to run QEMU: exit status " + str(ret) + ". Command line was:\n" + qemu_cmdline)
# Parent process done
sys.exit(0)
# In the child process: use _exit to terminate
retry = 0
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
while (retry < 10):
sleep(1);
try:
s.connect(qmp_sock)
print "Connected to QMP"
break;
except:
pass
retry = retry + 1
print "Failed to connect to QMP, attempt " + str(retry)
if (retry >= 10):
print "Failed to connect to QMP"
_exit(1)
# skip info about protocol
dat = s.recv(100000)
# need to run qmp_capabilities before next command works
s.send("{\"execute\" : \"qmp_capabilities\" }")
dat = s.recv(100000)
# Get the PID for each guest core
s.send("{\"execute\" : \"query-cpus\"}")
dat = s.recv(100000)
a = json.loads(dat)["return"];
if (len(a) != n_cores*n_threads):
print "Configuration mismatch: " + str(len(a)) + " vCPU reported by QMP, instead of expected " + str(n_cores*n_threads)
_exit(1)
print "QMP reported " + str(len(a)) + " vCPU, as expected"
if (n_threads == 1):
idx = 0;
for core in a:
cm = str(hex(1 << cores[idx][0]))
pid = str(core["thread_id"])
system("taskset -p " + cm + " " + pid + " > /dev/null")
idx = idx + 1
elif (n_threads == 2):
idx = 0;
prev = 0;
for core in a:
cm = str(hex(1 << cores[idx][prev]))
pid = str(core["thread_id"])
system("taskset -p " + cm + " " + pid + " > /dev/null")
prev = prev + 1;
if (prev == 2):
idx = idx + 1;
prev = 0
else:
print "Not implemented yet: more than 2 threads per core"
_exit(1)
print "Core affinitization completed"
_exit(0)
|