policy_static_test.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cpumanager
  14. import (
  15. "fmt"
  16. "reflect"
  17. "testing"
  18. v1 "k8s.io/api/core/v1"
  19. "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state"
  20. "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology"
  21. "k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
  22. "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager"
  23. "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask"
  24. )
  25. type staticPolicyTest struct {
  26. description string
  27. topo *topology.CPUTopology
  28. numReservedCPUs int
  29. podUID string
  30. containerName string
  31. stAssignments state.ContainerCPUAssignments
  32. stDefaultCPUSet cpuset.CPUSet
  33. pod *v1.Pod
  34. expErr error
  35. expCPUAlloc bool
  36. expCSet cpuset.CPUSet
  37. }
  38. func TestStaticPolicyName(t *testing.T) {
  39. policy, _ := NewStaticPolicy(topoSingleSocketHT, 1, cpuset.NewCPUSet(), topologymanager.NewFakeManager())
  40. policyName := policy.Name()
  41. if policyName != "static" {
  42. t.Errorf("StaticPolicy Name() error. expected: static, returned: %v",
  43. policyName)
  44. }
  45. }
  46. func TestStaticPolicyStart(t *testing.T) {
  47. testCases := []staticPolicyTest{
  48. {
  49. description: "non-corrupted state",
  50. topo: topoDualSocketHT,
  51. stAssignments: state.ContainerCPUAssignments{
  52. "fakePod": map[string]cpuset.CPUSet{
  53. "0": cpuset.NewCPUSet(0),
  54. },
  55. },
  56. stDefaultCPUSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  57. expCSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  58. },
  59. {
  60. description: "empty cpuset",
  61. topo: topoDualSocketHT,
  62. numReservedCPUs: 1,
  63. stAssignments: state.ContainerCPUAssignments{},
  64. stDefaultCPUSet: cpuset.NewCPUSet(),
  65. expCSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  66. },
  67. {
  68. description: "reserved cores 0 & 6 are not present in available cpuset",
  69. topo: topoDualSocketHT,
  70. numReservedCPUs: 2,
  71. stAssignments: state.ContainerCPUAssignments{},
  72. stDefaultCPUSet: cpuset.NewCPUSet(0, 1),
  73. expErr: fmt.Errorf("not all reserved cpus: \"0,6\" are present in defaultCpuSet: \"0-1\""),
  74. },
  75. {
  76. description: "assigned core 2 is still present in available cpuset",
  77. topo: topoDualSocketHT,
  78. stAssignments: state.ContainerCPUAssignments{
  79. "fakePod": map[string]cpuset.CPUSet{
  80. "0": cpuset.NewCPUSet(0, 1, 2),
  81. },
  82. },
  83. stDefaultCPUSet: cpuset.NewCPUSet(2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  84. expErr: fmt.Errorf("pod: fakePod, container: 0 cpuset: \"0-2\" overlaps with default cpuset \"2-11\""),
  85. },
  86. {
  87. description: "core 12 is not present in topology but is in state cpuset",
  88. topo: topoDualSocketHT,
  89. stAssignments: state.ContainerCPUAssignments{
  90. "fakePod": map[string]cpuset.CPUSet{
  91. "0": cpuset.NewCPUSet(0, 1, 2),
  92. "1": cpuset.NewCPUSet(3, 4),
  93. },
  94. },
  95. stDefaultCPUSet: cpuset.NewCPUSet(5, 6, 7, 8, 9, 10, 11, 12),
  96. expErr: fmt.Errorf("current set of available CPUs \"0-11\" doesn't match with CPUs in state \"0-12\""),
  97. },
  98. {
  99. description: "core 11 is present in topology but is not in state cpuset",
  100. topo: topoDualSocketHT,
  101. stAssignments: state.ContainerCPUAssignments{
  102. "fakePod": map[string]cpuset.CPUSet{
  103. "0": cpuset.NewCPUSet(0, 1, 2),
  104. "1": cpuset.NewCPUSet(3, 4),
  105. },
  106. },
  107. stDefaultCPUSet: cpuset.NewCPUSet(5, 6, 7, 8, 9, 10),
  108. expErr: fmt.Errorf("current set of available CPUs \"0-11\" doesn't match with CPUs in state \"0-10\""),
  109. },
  110. }
  111. for _, testCase := range testCases {
  112. t.Run(testCase.description, func(t *testing.T) {
  113. p, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.NewCPUSet(), topologymanager.NewFakeManager())
  114. policy := p.(*staticPolicy)
  115. st := &mockState{
  116. assignments: testCase.stAssignments,
  117. defaultCPUSet: testCase.stDefaultCPUSet,
  118. }
  119. err := policy.Start(st)
  120. if !reflect.DeepEqual(err, testCase.expErr) {
  121. t.Errorf("StaticPolicy Start() error (%v). expected error: %v but got: %v",
  122. testCase.description, testCase.expErr, err)
  123. }
  124. if err != nil {
  125. return
  126. }
  127. if !testCase.stDefaultCPUSet.IsEmpty() {
  128. for cpuid := 1; cpuid < policy.topology.NumCPUs; cpuid++ {
  129. if !st.defaultCPUSet.Contains(cpuid) {
  130. t.Errorf("StaticPolicy Start() error. expected cpuid %d to be present in defaultCPUSet", cpuid)
  131. }
  132. }
  133. }
  134. if !st.GetDefaultCPUSet().Equals(testCase.expCSet) {
  135. t.Errorf("State CPUSet is different than expected. Have %q wants: %q", st.GetDefaultCPUSet(),
  136. testCase.expCSet)
  137. }
  138. })
  139. }
  140. }
  141. func TestStaticPolicyAdd(t *testing.T) {
  142. largeTopoBuilder := cpuset.NewBuilder()
  143. largeTopoSock0Builder := cpuset.NewBuilder()
  144. largeTopoSock1Builder := cpuset.NewBuilder()
  145. largeTopo := *topoQuadSocketFourWayHT
  146. for cpuid, val := range largeTopo.CPUDetails {
  147. largeTopoBuilder.Add(cpuid)
  148. if val.SocketID == 0 {
  149. largeTopoSock0Builder.Add(cpuid)
  150. } else if val.SocketID == 1 {
  151. largeTopoSock1Builder.Add(cpuid)
  152. }
  153. }
  154. largeTopoCPUSet := largeTopoBuilder.Result()
  155. largeTopoSock0CPUSet := largeTopoSock0Builder.Result()
  156. largeTopoSock1CPUSet := largeTopoSock1Builder.Result()
  157. testCases := []staticPolicyTest{
  158. {
  159. description: "GuPodSingleCore, SingleSocketHT, ExpectError",
  160. topo: topoSingleSocketHT,
  161. numReservedCPUs: 1,
  162. stAssignments: state.ContainerCPUAssignments{},
  163. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
  164. pod: makePod("fakePod", "fakeContainer2", "8000m", "8000m"),
  165. expErr: fmt.Errorf("not enough cpus available to satisfy request"),
  166. expCPUAlloc: false,
  167. expCSet: cpuset.NewCPUSet(),
  168. },
  169. {
  170. description: "GuPodSingleCore, SingleSocketHT, ExpectAllocOneCPU",
  171. topo: topoSingleSocketHT,
  172. numReservedCPUs: 1,
  173. stAssignments: state.ContainerCPUAssignments{},
  174. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
  175. pod: makePod("fakePod", "fakeContainer2", "1000m", "1000m"),
  176. expErr: nil,
  177. expCPUAlloc: true,
  178. expCSet: cpuset.NewCPUSet(4), // expect sibling of partial core
  179. },
  180. {
  181. description: "GuPodMultipleCores, SingleSocketHT, ExpectAllocOneCore",
  182. topo: topoSingleSocketHT,
  183. numReservedCPUs: 1,
  184. stAssignments: state.ContainerCPUAssignments{
  185. "fakePod": map[string]cpuset.CPUSet{
  186. "fakeContainer100": cpuset.NewCPUSet(2, 3, 6, 7),
  187. },
  188. },
  189. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 4, 5),
  190. pod: makePod("fakePod", "fakeContainer3", "2000m", "2000m"),
  191. expErr: nil,
  192. expCPUAlloc: true,
  193. expCSet: cpuset.NewCPUSet(1, 5),
  194. },
  195. {
  196. description: "GuPodMultipleCores, SingleSocketHT, ExpectSameAllocation",
  197. topo: topoSingleSocketHT,
  198. numReservedCPUs: 1,
  199. stAssignments: state.ContainerCPUAssignments{
  200. "fakePod": map[string]cpuset.CPUSet{
  201. "fakeContainer3": cpuset.NewCPUSet(2, 3, 6, 7),
  202. },
  203. },
  204. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 4, 5),
  205. pod: makePod("fakePod", "fakeContainer3", "4000m", "4000m"),
  206. expErr: nil,
  207. expCPUAlloc: true,
  208. expCSet: cpuset.NewCPUSet(2, 3, 6, 7),
  209. },
  210. {
  211. description: "GuPodMultipleCores, DualSocketHT, ExpectAllocOneSocket",
  212. topo: topoDualSocketHT,
  213. numReservedCPUs: 1,
  214. stAssignments: state.ContainerCPUAssignments{
  215. "fakePod": map[string]cpuset.CPUSet{
  216. "fakeContainer100": cpuset.NewCPUSet(2),
  217. },
  218. },
  219. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  220. pod: makePod("fakePod", "fakeContainer3", "6000m", "6000m"),
  221. expErr: nil,
  222. expCPUAlloc: true,
  223. expCSet: cpuset.NewCPUSet(1, 3, 5, 7, 9, 11),
  224. },
  225. {
  226. description: "GuPodMultipleCores, DualSocketHT, ExpectAllocThreeCores",
  227. topo: topoDualSocketHT,
  228. numReservedCPUs: 1,
  229. stAssignments: state.ContainerCPUAssignments{
  230. "fakePod": map[string]cpuset.CPUSet{
  231. "fakeContainer100": cpuset.NewCPUSet(1, 5),
  232. },
  233. },
  234. stDefaultCPUSet: cpuset.NewCPUSet(0, 2, 3, 4, 6, 7, 8, 9, 10, 11),
  235. pod: makePod("fakePod", "fakeContainer3", "6000m", "6000m"),
  236. expErr: nil,
  237. expCPUAlloc: true,
  238. expCSet: cpuset.NewCPUSet(2, 3, 4, 8, 9, 10),
  239. },
  240. {
  241. description: "GuPodMultipleCores, DualSocketNoHT, ExpectAllocOneSocket",
  242. topo: topoDualSocketNoHT,
  243. numReservedCPUs: 1,
  244. stAssignments: state.ContainerCPUAssignments{
  245. "fakePod": map[string]cpuset.CPUSet{
  246. "fakeContainer100": cpuset.NewCPUSet(),
  247. },
  248. },
  249. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 4, 5, 6, 7),
  250. pod: makePod("fakePod", "fakeContainer1", "4000m", "4000m"),
  251. expErr: nil,
  252. expCPUAlloc: true,
  253. expCSet: cpuset.NewCPUSet(4, 5, 6, 7),
  254. },
  255. {
  256. description: "GuPodMultipleCores, DualSocketNoHT, ExpectAllocFourCores",
  257. topo: topoDualSocketNoHT,
  258. numReservedCPUs: 1,
  259. stAssignments: state.ContainerCPUAssignments{
  260. "fakePod": map[string]cpuset.CPUSet{
  261. "fakeContainer100": cpuset.NewCPUSet(4, 5),
  262. },
  263. },
  264. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 6, 7),
  265. pod: makePod("fakePod", "fakeContainer1", "4000m", "4000m"),
  266. expErr: nil,
  267. expCPUAlloc: true,
  268. expCSet: cpuset.NewCPUSet(1, 3, 6, 7),
  269. },
  270. {
  271. description: "GuPodMultipleCores, DualSocketHT, ExpectAllocOneSocketOneCore",
  272. topo: topoDualSocketHT,
  273. numReservedCPUs: 1,
  274. stAssignments: state.ContainerCPUAssignments{
  275. "fakePod": map[string]cpuset.CPUSet{
  276. "fakeContainer100": cpuset.NewCPUSet(2),
  277. },
  278. },
  279. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  280. pod: makePod("fakePod", "fakeContainer3", "8000m", "8000m"),
  281. expErr: nil,
  282. expCPUAlloc: true,
  283. expCSet: cpuset.NewCPUSet(1, 3, 4, 5, 7, 9, 10, 11),
  284. },
  285. {
  286. description: "NonGuPod, SingleSocketHT, NoAlloc",
  287. topo: topoSingleSocketHT,
  288. numReservedCPUs: 1,
  289. stAssignments: state.ContainerCPUAssignments{},
  290. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
  291. pod: makePod("fakePod", "fakeContainer1", "1000m", "2000m"),
  292. expErr: nil,
  293. expCPUAlloc: false,
  294. expCSet: cpuset.NewCPUSet(),
  295. },
  296. {
  297. description: "GuPodNonIntegerCore, SingleSocketHT, NoAlloc",
  298. topo: topoSingleSocketHT,
  299. numReservedCPUs: 1,
  300. stAssignments: state.ContainerCPUAssignments{},
  301. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
  302. pod: makePod("fakePod", "fakeContainer4", "977m", "977m"),
  303. expErr: nil,
  304. expCPUAlloc: false,
  305. expCSet: cpuset.NewCPUSet(),
  306. },
  307. {
  308. description: "GuPodMultipleCores, SingleSocketHT, NoAllocExpectError",
  309. topo: topoSingleSocketHT,
  310. numReservedCPUs: 1,
  311. stAssignments: state.ContainerCPUAssignments{
  312. "fakePod": map[string]cpuset.CPUSet{
  313. "fakeContainer100": cpuset.NewCPUSet(1, 2, 3, 4, 5, 6),
  314. },
  315. },
  316. stDefaultCPUSet: cpuset.NewCPUSet(0, 7),
  317. pod: makePod("fakePod", "fakeContainer5", "2000m", "2000m"),
  318. expErr: fmt.Errorf("not enough cpus available to satisfy request"),
  319. expCPUAlloc: false,
  320. expCSet: cpuset.NewCPUSet(),
  321. },
  322. {
  323. description: "GuPodMultipleCores, DualSocketHT, NoAllocExpectError",
  324. topo: topoDualSocketHT,
  325. numReservedCPUs: 1,
  326. stAssignments: state.ContainerCPUAssignments{
  327. "fakePod": map[string]cpuset.CPUSet{
  328. "fakeContainer100": cpuset.NewCPUSet(1, 2, 3),
  329. },
  330. },
  331. stDefaultCPUSet: cpuset.NewCPUSet(0, 4, 5, 6, 7, 8, 9, 10, 11),
  332. pod: makePod("fakePod", "fakeContainer5", "10000m", "10000m"),
  333. expErr: fmt.Errorf("not enough cpus available to satisfy request"),
  334. expCPUAlloc: false,
  335. expCSet: cpuset.NewCPUSet(),
  336. },
  337. {
  338. // All the CPUs from Socket 0 are available. Some CPUs from each
  339. // Socket have been already assigned.
  340. // Expect all CPUs from Socket 0.
  341. description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocSock0",
  342. topo: topoQuadSocketFourWayHT,
  343. stAssignments: state.ContainerCPUAssignments{
  344. "fakePod": map[string]cpuset.CPUSet{
  345. "fakeContainer100": cpuset.NewCPUSet(3, 11, 4, 5, 6, 7),
  346. },
  347. },
  348. stDefaultCPUSet: largeTopoCPUSet.Difference(cpuset.NewCPUSet(3, 11, 4, 5, 6, 7)),
  349. pod: makePod("fakePod", "fakeContainer5", "72000m", "72000m"),
  350. expErr: nil,
  351. expCPUAlloc: true,
  352. expCSet: largeTopoSock0CPUSet,
  353. },
  354. {
  355. // Only 2 full cores from three Sockets and some partial cores are available.
  356. // Expect CPUs from the 2 full cores available from the three Sockets.
  357. description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocAllFullCoresFromThreeSockets",
  358. topo: topoQuadSocketFourWayHT,
  359. stAssignments: state.ContainerCPUAssignments{
  360. "fakePod": map[string]cpuset.CPUSet{
  361. "fakeContainer100": largeTopoCPUSet.Difference(cpuset.NewCPUSet(1, 25, 13, 38, 2, 9, 11, 35, 23, 48, 12, 51,
  362. 53, 173, 113, 233, 54, 61)),
  363. },
  364. },
  365. stDefaultCPUSet: cpuset.NewCPUSet(1, 25, 13, 38, 2, 9, 11, 35, 23, 48, 12, 51, 53, 173, 113, 233, 54, 61),
  366. pod: makePod("fakePod", "fakeCcontainer5", "12000m", "12000m"),
  367. expErr: nil,
  368. expCPUAlloc: true,
  369. expCSet: cpuset.NewCPUSet(1, 25, 13, 38, 11, 35, 23, 48, 53, 173, 113, 233),
  370. },
  371. {
  372. // All CPUs from Socket 1, 1 full core and some partial cores are available.
  373. // Expect all CPUs from Socket 1 and the hyper-threads from the full core.
  374. description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocAllSock1+FullCore",
  375. topo: topoQuadSocketFourWayHT,
  376. stAssignments: state.ContainerCPUAssignments{
  377. "fakePod": map[string]cpuset.CPUSet{
  378. "fakeContainer100": largeTopoCPUSet.Difference(largeTopoSock1CPUSet.Union(cpuset.NewCPUSet(10, 34, 22, 47, 53,
  379. 173, 61, 181, 108, 228, 115, 235))),
  380. },
  381. },
  382. stDefaultCPUSet: largeTopoSock1CPUSet.Union(cpuset.NewCPUSet(10, 34, 22, 47, 53, 173, 61, 181, 108, 228,
  383. 115, 235)),
  384. pod: makePod("fakePod", "fakeContainer5", "76000m", "76000m"),
  385. expErr: nil,
  386. expCPUAlloc: true,
  387. expCSet: largeTopoSock1CPUSet.Union(cpuset.NewCPUSet(10, 34, 22, 47)),
  388. },
  389. {
  390. // Only partial cores are available in the entire system.
  391. // Expect allocation of all the CPUs from the partial cores.
  392. description: "GuPodMultipleCores, topoQuadSocketFourWayHT, ExpectAllocCPUs",
  393. topo: topoQuadSocketFourWayHT,
  394. stAssignments: state.ContainerCPUAssignments{
  395. "fakePod": map[string]cpuset.CPUSet{
  396. "fakeContainer100": largeTopoCPUSet.Difference(cpuset.NewCPUSet(10, 11, 53, 37, 55, 67, 52)),
  397. },
  398. },
  399. stDefaultCPUSet: cpuset.NewCPUSet(10, 11, 53, 67, 52),
  400. pod: makePod("fakePod", "fakeContainer5", "5000m", "5000m"),
  401. expErr: nil,
  402. expCPUAlloc: true,
  403. expCSet: cpuset.NewCPUSet(10, 11, 53, 67, 52),
  404. },
  405. {
  406. // Only 7 CPUs are available.
  407. // Pod requests 76 cores.
  408. // Error is expect since available CPUs are less than the request.
  409. description: "GuPodMultipleCores, topoQuadSocketFourWayHT, NoAlloc",
  410. topo: topoQuadSocketFourWayHT,
  411. stAssignments: state.ContainerCPUAssignments{
  412. "fakePod": map[string]cpuset.CPUSet{
  413. "fakeContainer100": largeTopoCPUSet.Difference(cpuset.NewCPUSet(10, 11, 53, 37, 55, 67, 52)),
  414. },
  415. },
  416. stDefaultCPUSet: cpuset.NewCPUSet(10, 11, 53, 37, 55, 67, 52),
  417. pod: makePod("fakePod", "fakeContainer5", "76000m", "76000m"),
  418. expErr: fmt.Errorf("not enough cpus available to satisfy request"),
  419. expCPUAlloc: false,
  420. expCSet: cpuset.NewCPUSet(),
  421. },
  422. }
  423. for _, testCase := range testCases {
  424. policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.NewCPUSet(), topologymanager.NewFakeManager())
  425. st := &mockState{
  426. assignments: testCase.stAssignments,
  427. defaultCPUSet: testCase.stDefaultCPUSet,
  428. }
  429. container := &testCase.pod.Spec.Containers[0]
  430. err := policy.AddContainer(st, testCase.pod, container)
  431. if !reflect.DeepEqual(err, testCase.expErr) {
  432. t.Errorf("StaticPolicy AddContainer() error (%v). expected add error: %v but got: %v",
  433. testCase.description, testCase.expErr, err)
  434. }
  435. if testCase.expCPUAlloc {
  436. cset, found := st.assignments[string(testCase.pod.UID)][container.Name]
  437. if !found {
  438. t.Errorf("StaticPolicy AddContainer() error (%v). expected container %v to be present in assignments %v",
  439. testCase.description, container.Name, st.assignments)
  440. }
  441. if !reflect.DeepEqual(cset, testCase.expCSet) {
  442. t.Errorf("StaticPolicy AddContainer() error (%v). expected cpuset %v but got %v",
  443. testCase.description, testCase.expCSet, cset)
  444. }
  445. if !cset.Intersection(st.defaultCPUSet).IsEmpty() {
  446. t.Errorf("StaticPolicy AddContainer() error (%v). expected cpuset %v to be disoint from the shared cpuset %v",
  447. testCase.description, cset, st.defaultCPUSet)
  448. }
  449. }
  450. if !testCase.expCPUAlloc {
  451. _, found := st.assignments[string(testCase.pod.UID)][container.Name]
  452. if found {
  453. t.Errorf("StaticPolicy AddContainer() error (%v). Did not expect container %v to be present in assignments %v",
  454. testCase.description, container.Name, st.assignments)
  455. }
  456. }
  457. }
  458. }
  459. func TestStaticPolicyRemove(t *testing.T) {
  460. testCases := []staticPolicyTest{
  461. {
  462. description: "SingleSocketHT, DeAllocOneContainer",
  463. topo: topoSingleSocketHT,
  464. podUID: "fakePod",
  465. containerName: "fakeContainer1",
  466. stAssignments: state.ContainerCPUAssignments{
  467. "fakePod": map[string]cpuset.CPUSet{
  468. "fakeContainer1": cpuset.NewCPUSet(1, 2, 3),
  469. },
  470. },
  471. stDefaultCPUSet: cpuset.NewCPUSet(4, 5, 6, 7),
  472. expCSet: cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7),
  473. },
  474. {
  475. description: "SingleSocketHT, DeAllocOneContainer, BeginEmpty",
  476. topo: topoSingleSocketHT,
  477. podUID: "fakePod",
  478. containerName: "fakeContainer1",
  479. stAssignments: state.ContainerCPUAssignments{
  480. "fakePod": map[string]cpuset.CPUSet{
  481. "fakeContainer1": cpuset.NewCPUSet(1, 2, 3),
  482. "fakeContainer2": cpuset.NewCPUSet(4, 5, 6, 7),
  483. },
  484. },
  485. stDefaultCPUSet: cpuset.NewCPUSet(),
  486. expCSet: cpuset.NewCPUSet(1, 2, 3),
  487. },
  488. {
  489. description: "SingleSocketHT, DeAllocTwoContainer",
  490. topo: topoSingleSocketHT,
  491. podUID: "fakePod",
  492. containerName: "fakeContainer1",
  493. stAssignments: state.ContainerCPUAssignments{
  494. "fakePod": map[string]cpuset.CPUSet{
  495. "fakeContainer1": cpuset.NewCPUSet(1, 3, 5),
  496. "fakeContainer2": cpuset.NewCPUSet(2, 4),
  497. },
  498. },
  499. stDefaultCPUSet: cpuset.NewCPUSet(6, 7),
  500. expCSet: cpuset.NewCPUSet(1, 3, 5, 6, 7),
  501. },
  502. {
  503. description: "SingleSocketHT, NoDeAlloc",
  504. topo: topoSingleSocketHT,
  505. podUID: "fakePod",
  506. containerName: "fakeContainer2",
  507. stAssignments: state.ContainerCPUAssignments{
  508. "fakePod": map[string]cpuset.CPUSet{
  509. "fakeContainer1": cpuset.NewCPUSet(1, 3, 5),
  510. },
  511. },
  512. stDefaultCPUSet: cpuset.NewCPUSet(2, 4, 6, 7),
  513. expCSet: cpuset.NewCPUSet(2, 4, 6, 7),
  514. },
  515. }
  516. for _, testCase := range testCases {
  517. policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.NewCPUSet(), topologymanager.NewFakeManager())
  518. st := &mockState{
  519. assignments: testCase.stAssignments,
  520. defaultCPUSet: testCase.stDefaultCPUSet,
  521. }
  522. policy.RemoveContainer(st, testCase.podUID, testCase.containerName)
  523. if !reflect.DeepEqual(st.defaultCPUSet, testCase.expCSet) {
  524. t.Errorf("StaticPolicy RemoveContainer() error (%v). expected default cpuset %v but got %v",
  525. testCase.description, testCase.expCSet, st.defaultCPUSet)
  526. }
  527. if _, found := st.assignments[testCase.podUID][testCase.containerName]; found {
  528. t.Errorf("StaticPolicy RemoveContainer() error (%v). expected (pod %v, container %v) not be in assignments %v",
  529. testCase.description, testCase.podUID, testCase.containerName, st.assignments)
  530. }
  531. }
  532. }
  533. func TestTopologyAwareAllocateCPUs(t *testing.T) {
  534. testCases := []struct {
  535. description string
  536. topo *topology.CPUTopology
  537. stAssignments state.ContainerCPUAssignments
  538. stDefaultCPUSet cpuset.CPUSet
  539. numRequested int
  540. socketMask bitmask.BitMask
  541. expCSet cpuset.CPUSet
  542. }{
  543. {
  544. description: "Request 2 CPUs, No BitMask",
  545. topo: topoDualSocketHT,
  546. stAssignments: state.ContainerCPUAssignments{},
  547. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  548. numRequested: 2,
  549. socketMask: nil,
  550. expCSet: cpuset.NewCPUSet(0, 6),
  551. },
  552. {
  553. description: "Request 2 CPUs, BitMask on Socket 0",
  554. topo: topoDualSocketHT,
  555. stAssignments: state.ContainerCPUAssignments{},
  556. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  557. numRequested: 2,
  558. socketMask: func() bitmask.BitMask {
  559. mask, _ := bitmask.NewBitMask(0)
  560. return mask
  561. }(),
  562. expCSet: cpuset.NewCPUSet(0, 6),
  563. },
  564. {
  565. description: "Request 2 CPUs, BitMask on Socket 1",
  566. topo: topoDualSocketHT,
  567. stAssignments: state.ContainerCPUAssignments{},
  568. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  569. numRequested: 2,
  570. socketMask: func() bitmask.BitMask {
  571. mask, _ := bitmask.NewBitMask(1)
  572. return mask
  573. }(),
  574. expCSet: cpuset.NewCPUSet(1, 7),
  575. },
  576. {
  577. description: "Request 8 CPUs, BitMask on Socket 0",
  578. topo: topoDualSocketHT,
  579. stAssignments: state.ContainerCPUAssignments{},
  580. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  581. numRequested: 8,
  582. socketMask: func() bitmask.BitMask {
  583. mask, _ := bitmask.NewBitMask(0)
  584. return mask
  585. }(),
  586. expCSet: cpuset.NewCPUSet(0, 6, 2, 8, 4, 10, 1, 7),
  587. },
  588. {
  589. description: "Request 8 CPUs, BitMask on Socket 1",
  590. topo: topoDualSocketHT,
  591. stAssignments: state.ContainerCPUAssignments{},
  592. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  593. numRequested: 8,
  594. socketMask: func() bitmask.BitMask {
  595. mask, _ := bitmask.NewBitMask(1)
  596. return mask
  597. }(),
  598. expCSet: cpuset.NewCPUSet(1, 7, 3, 9, 5, 11, 0, 6),
  599. },
  600. }
  601. for _, tc := range testCases {
  602. p, _ := NewStaticPolicy(tc.topo, 0, cpuset.NewCPUSet(), topologymanager.NewFakeManager())
  603. policy := p.(*staticPolicy)
  604. st := &mockState{
  605. assignments: tc.stAssignments,
  606. defaultCPUSet: tc.stDefaultCPUSet,
  607. }
  608. err := policy.Start(st)
  609. if err != nil {
  610. t.Errorf("StaticPolicy Start() error (%v)", err)
  611. continue
  612. }
  613. cset, err := policy.allocateCPUs(st, tc.numRequested, tc.socketMask)
  614. if err != nil {
  615. t.Errorf("StaticPolicy allocateCPUs() error (%v). expected CPUSet %v not error %v",
  616. tc.description, tc.expCSet, err)
  617. continue
  618. }
  619. if !reflect.DeepEqual(tc.expCSet, cset) {
  620. t.Errorf("StaticPolicy allocateCPUs() error (%v). expected CPUSet %v but got %v",
  621. tc.description, tc.expCSet, cset)
  622. }
  623. }
  624. }
  625. // above test cases are without kubelet --reserved-cpus cmd option
  626. // the following tests are with --reserved-cpus configured
  627. type staticPolicyTestWithResvList struct {
  628. description string
  629. topo *topology.CPUTopology
  630. numReservedCPUs int
  631. reserved cpuset.CPUSet
  632. stAssignments state.ContainerCPUAssignments
  633. stDefaultCPUSet cpuset.CPUSet
  634. pod *v1.Pod
  635. expErr error
  636. expNewErr error
  637. expCPUAlloc bool
  638. expCSet cpuset.CPUSet
  639. }
  640. func TestStaticPolicyStartWithResvList(t *testing.T) {
  641. testCases := []staticPolicyTestWithResvList{
  642. {
  643. description: "empty cpuset",
  644. topo: topoDualSocketHT,
  645. numReservedCPUs: 2,
  646. reserved: cpuset.NewCPUSet(0, 1),
  647. stAssignments: state.ContainerCPUAssignments{},
  648. stDefaultCPUSet: cpuset.NewCPUSet(),
  649. expCSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  650. },
  651. {
  652. description: "reserved cores 0 & 1 are not present in available cpuset",
  653. topo: topoDualSocketHT,
  654. numReservedCPUs: 2,
  655. reserved: cpuset.NewCPUSet(0, 1),
  656. stAssignments: state.ContainerCPUAssignments{},
  657. stDefaultCPUSet: cpuset.NewCPUSet(2, 3, 4, 5),
  658. expErr: fmt.Errorf("not all reserved cpus: \"0-1\" are present in defaultCpuSet: \"2-5\""),
  659. },
  660. {
  661. description: "inconsistency between numReservedCPUs and reserved",
  662. topo: topoDualSocketHT,
  663. numReservedCPUs: 1,
  664. reserved: cpuset.NewCPUSet(0, 1),
  665. stAssignments: state.ContainerCPUAssignments{},
  666. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  667. expNewErr: fmt.Errorf("[cpumanager] unable to reserve the required amount of CPUs (size of 0-1 did not equal 1)"),
  668. },
  669. }
  670. for _, testCase := range testCases {
  671. t.Run(testCase.description, func(t *testing.T) {
  672. p, err := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, testCase.reserved, topologymanager.NewFakeManager())
  673. if !reflect.DeepEqual(err, testCase.expNewErr) {
  674. t.Errorf("StaticPolicy Start() error (%v). expected error: %v but got: %v",
  675. testCase.description, testCase.expNewErr, err)
  676. }
  677. if err != nil {
  678. return
  679. }
  680. policy := p.(*staticPolicy)
  681. st := &mockState{
  682. assignments: testCase.stAssignments,
  683. defaultCPUSet: testCase.stDefaultCPUSet,
  684. }
  685. err = policy.Start(st)
  686. if !reflect.DeepEqual(err, testCase.expErr) {
  687. t.Errorf("StaticPolicy Start() error (%v). expected error: %v but got: %v",
  688. testCase.description, testCase.expErr, err)
  689. }
  690. if err != nil {
  691. return
  692. }
  693. if !st.GetDefaultCPUSet().Equals(testCase.expCSet) {
  694. t.Errorf("State CPUSet is different than expected. Have %q wants: %q", st.GetDefaultCPUSet(),
  695. testCase.expCSet)
  696. }
  697. })
  698. }
  699. }
  700. func TestStaticPolicyAddWithResvList(t *testing.T) {
  701. testCases := []staticPolicyTestWithResvList{
  702. {
  703. description: "GuPodSingleCore, SingleSocketHT, ExpectError",
  704. topo: topoSingleSocketHT,
  705. numReservedCPUs: 1,
  706. reserved: cpuset.NewCPUSet(0),
  707. stAssignments: state.ContainerCPUAssignments{},
  708. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
  709. pod: makePod("fakePod", "fakeContainer2", "8000m", "8000m"),
  710. expErr: fmt.Errorf("not enough cpus available to satisfy request"),
  711. expCPUAlloc: false,
  712. expCSet: cpuset.NewCPUSet(),
  713. },
  714. {
  715. description: "GuPodSingleCore, SingleSocketHT, ExpectAllocOneCPU",
  716. topo: topoSingleSocketHT,
  717. numReservedCPUs: 2,
  718. reserved: cpuset.NewCPUSet(0, 1),
  719. stAssignments: state.ContainerCPUAssignments{},
  720. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7),
  721. pod: makePod("fakePod", "fakeContainer2", "1000m", "1000m"),
  722. expErr: nil,
  723. expCPUAlloc: true,
  724. expCSet: cpuset.NewCPUSet(4), // expect sibling of partial core
  725. },
  726. {
  727. description: "GuPodMultipleCores, SingleSocketHT, ExpectAllocOneCore",
  728. topo: topoSingleSocketHT,
  729. numReservedCPUs: 2,
  730. reserved: cpuset.NewCPUSet(0, 1),
  731. stAssignments: state.ContainerCPUAssignments{
  732. "fakePod": map[string]cpuset.CPUSet{
  733. "fakeContainer100": cpuset.NewCPUSet(2, 3, 6, 7),
  734. },
  735. },
  736. stDefaultCPUSet: cpuset.NewCPUSet(0, 1, 4, 5),
  737. pod: makePod("fakePod", "fakeContainer3", "2000m", "2000m"),
  738. expErr: nil,
  739. expCPUAlloc: true,
  740. expCSet: cpuset.NewCPUSet(4, 5),
  741. },
  742. }
  743. for _, testCase := range testCases {
  744. policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, testCase.reserved, topologymanager.NewFakeManager())
  745. st := &mockState{
  746. assignments: testCase.stAssignments,
  747. defaultCPUSet: testCase.stDefaultCPUSet,
  748. }
  749. container := &testCase.pod.Spec.Containers[0]
  750. err := policy.AddContainer(st, testCase.pod, container)
  751. if !reflect.DeepEqual(err, testCase.expErr) {
  752. t.Errorf("StaticPolicy AddContainer() error (%v). expected add error: %v but got: %v",
  753. testCase.description, testCase.expErr, err)
  754. }
  755. if testCase.expCPUAlloc {
  756. cset, found := st.assignments[string(testCase.pod.UID)][container.Name]
  757. if !found {
  758. t.Errorf("StaticPolicy AddContainer() error (%v). expected container %v to be present in assignments %v",
  759. testCase.description, container.Name, st.assignments)
  760. }
  761. if !reflect.DeepEqual(cset, testCase.expCSet) {
  762. t.Errorf("StaticPolicy AddContainer() error (%v). expected cpuset %v but got %v",
  763. testCase.description, testCase.expCSet, cset)
  764. }
  765. if !cset.Intersection(st.defaultCPUSet).IsEmpty() {
  766. t.Errorf("StaticPolicy AddContainer() error (%v). expected cpuset %v to be disoint from the shared cpuset %v",
  767. testCase.description, cset, st.defaultCPUSet)
  768. }
  769. }
  770. if !testCase.expCPUAlloc {
  771. _, found := st.assignments[string(testCase.pod.UID)][container.Name]
  772. if found {
  773. t.Errorf("StaticPolicy AddContainer() error (%v). Did not expect container %v to be present in assignments %v",
  774. testCase.description, container.Name, st.assignments)
  775. }
  776. }
  777. }
  778. }