1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18 
19 package org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 import org.junit.Assert;
25 
26 import org.apache.hadoop.yarn.util.resource.Resources;
27 import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceType;
28 import org.apache.hadoop.yarn.server.resourcemanager.resource.ResourceWeights;
29 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.policies.ComputeFairShares;
30 import org.junit.Before;
31 import org.junit.Test;
32 
33 /**
34  * Exercise the computeFairShares method in SchedulingAlgorithms.
35  */
36 public class TestComputeFairShares {
37   private List<Schedulable> scheds;
38 
39   @Before
setUp()40   public void setUp() throws Exception {
41     scheds = new ArrayList<Schedulable>();
42   }
43 
44   /**
45    * Basic test - pools with different demands that are all higher than their
46    * fair share (of 10 slots) should each get their fair share.
47    */
48   @Test
testEqualSharing()49   public void testEqualSharing() {
50     scheds.add(new FakeSchedulable());
51     scheds.add(new FakeSchedulable());
52     scheds.add(new FakeSchedulable());
53     scheds.add(new FakeSchedulable());
54     ComputeFairShares.computeShares(scheds,
55         Resources.createResource(40), ResourceType.MEMORY);
56     verifyMemoryShares(10, 10, 10, 10);
57   }
58 
59   /**
60    * In this test, pool 4 has a smaller demand than the 40 / 4 = 10 slots that
61    * it would be assigned with equal sharing. It should only get the 3 slots
62    * it demands. The other pools must then split the remaining 37 slots, but
63    * pool 3, with 11 slots demanded, is now below its share of 37/3 ~= 12.3,
64    * so it only gets 11 slots. Pools 1 and 2 split the rest and get 13 each.
65    */
66   @Test
testLowMaxShares()67   public void testLowMaxShares() {
68     scheds.add(new FakeSchedulable(0, 100));
69     scheds.add(new FakeSchedulable(0, 50));
70     scheds.add(new FakeSchedulable(0, 11));
71     scheds.add(new FakeSchedulable(0, 3));
72     ComputeFairShares.computeShares(scheds,
73         Resources.createResource(40), ResourceType.MEMORY);
74     verifyMemoryShares(13, 13, 11, 3);
75   }
76 
77 
78   /**
79    * In this test, some pools have minimum shares set. Pool 1 has a min share
80    * of 20 so it gets 20 slots. Pool 2 also has a min share of 20, but its
81    * demand is only 10 so it can only get 10 slots. The remaining pools have
82    * 10 slots to split between them. Pool 4 gets 3 slots because its demand is
83    * only 3, and pool 3 gets the remaining 7 slots. Pool 4 also had a min share
84    * of 2 slots but this should not affect the outcome.
85    */
86   @Test
testMinShares()87   public void testMinShares() {
88     scheds.add(new FakeSchedulable(20));
89     scheds.add(new FakeSchedulable(18));
90     scheds.add(new FakeSchedulable(0));
91     scheds.add(new FakeSchedulable(2));
92     ComputeFairShares.computeShares(scheds,
93         Resources.createResource(40), ResourceType.MEMORY);
94     verifyMemoryShares(20, 18, 0, 2);
95   }
96 
97   /**
98    * Basic test for weighted shares with no minimum shares and no low demands.
99    * Each pool should get slots in proportion to its weight.
100    */
101   @Test
testWeightedSharing()102   public void testWeightedSharing() {
103     scheds.add(new FakeSchedulable(0, 2.0));
104     scheds.add(new FakeSchedulable(0, 1.0));
105     scheds.add(new FakeSchedulable(0, 1.0));
106     scheds.add(new FakeSchedulable(0, 0.5));
107     ComputeFairShares.computeShares(scheds,
108         Resources.createResource(45), ResourceType.MEMORY);
109     verifyMemoryShares(20, 10, 10, 5);
110   }
111 
112   /**
113    * Weighted sharing test where pools 1 and 2 are now given lower demands than
114    * above. Pool 1 stops at 10 slots, leaving 35. If the remaining pools split
115    * this into a 1:1:0.5 ratio, they would get 14:14:7 slots respectively, but
116    * pool 2's demand is only 11, so it only gets 11. The remaining 2 pools split
117    * the 24 slots left into a 1:0.5 ratio, getting 16 and 8 slots respectively.
118    */
119   @Test
testWeightedSharingWithMaxShares()120   public void testWeightedSharingWithMaxShares() {
121     scheds.add(new FakeSchedulable(0, 10, 2.0));
122     scheds.add(new FakeSchedulable(0, 11, 1.0));
123     scheds.add(new FakeSchedulable(0, 30, 1.0));
124     scheds.add(new FakeSchedulable(0, 20, 0.5));
125     ComputeFairShares.computeShares(scheds,
126         Resources.createResource(45), ResourceType.MEMORY);
127     verifyMemoryShares(10, 11, 16, 8);
128   }
129 
130 
131   /**
132    * Weighted fair sharing test with min shares. As in the min share test above,
133    * pool 1 has a min share greater than its demand so it only gets its demand.
134    * Pool 3 has a min share of 15 even though its weight is very small, so it
135    * gets 15 slots. The remaining pools share the remaining 20 slots equally,
136    * getting 10 each. Pool 3's min share of 5 slots doesn't affect this.
137    */
138   @Test
testWeightedSharingWithMinShares()139   public void testWeightedSharingWithMinShares() {
140     scheds.add(new FakeSchedulable(20, 2.0));
141     scheds.add(new FakeSchedulable(0, 1.0));
142     scheds.add(new FakeSchedulable(5, 1.0));
143     scheds.add(new FakeSchedulable(15, 0.5));
144     ComputeFairShares.computeShares(scheds,
145         Resources.createResource(45), ResourceType.MEMORY);
146     verifyMemoryShares(20, 5, 5, 15);
147   }
148 
149   /**
150    * Test that shares are computed accurately even when the number of slots is
151    * very large.
152    */
153   @Test
testLargeShares()154   public void testLargeShares() {
155     int million = 1000 * 1000;
156     scheds.add(new FakeSchedulable());
157     scheds.add(new FakeSchedulable());
158     scheds.add(new FakeSchedulable());
159     scheds.add(new FakeSchedulable());
160     ComputeFairShares.computeShares(scheds,
161         Resources.createResource(40 * million), ResourceType.MEMORY);
162     verifyMemoryShares(10 * million, 10 * million, 10 * million, 10 * million);
163   }
164 
165   /**
166    * Test that being called on an empty list doesn't confuse the algorithm.
167    */
168   @Test
testEmptyList()169   public void testEmptyList() {
170     ComputeFairShares.computeShares(scheds,
171         Resources.createResource(40), ResourceType.MEMORY);
172     verifyMemoryShares();
173   }
174 
175   /**
176    * Test that CPU works as well as memory
177    */
178   @Test
testCPU()179   public void testCPU() {
180     scheds.add(new FakeSchedulable(Resources.createResource(0, 20),
181         new ResourceWeights(2.0f)));
182     scheds.add(new FakeSchedulable(Resources.createResource(0, 0),
183         new ResourceWeights(1.0f)));
184     scheds.add(new FakeSchedulable(Resources.createResource(0, 5),
185         new ResourceWeights(1.0f)));
186     scheds.add(new FakeSchedulable(Resources.createResource(0, 15),
187         new ResourceWeights(0.5f)));
188     ComputeFairShares.computeShares(scheds,
189         Resources.createResource(0, 45), ResourceType.CPU);
190     verifyCPUShares(20, 5, 5, 15);
191   }
192 
193   /**
194    * Check that a given list of shares have been assigned to this.scheds.
195    */
verifyMemoryShares(int... shares)196   private void verifyMemoryShares(int... shares) {
197     Assert.assertEquals(scheds.size(), shares.length);
198     for (int i = 0; i < shares.length; i++) {
199       Assert.assertEquals(shares[i], scheds.get(i).getFairShare().getMemory());
200     }
201   }
202 
203   /**
204    * Check that a given list of shares have been assigned to this.scheds.
205    */
verifyCPUShares(int... shares)206   private void verifyCPUShares(int... shares) {
207     Assert.assertEquals(scheds.size(), shares.length);
208     for (int i = 0; i < shares.length; i++) {
209       Assert.assertEquals(shares[i], scheds.get(i).getFairShare().getVirtualCores());
210     }
211   }
212 }
213