/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.flink.runtime.taskexecutor; import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.TaskManagerOptions; import org.apache.flink.core.memory.MemoryType; import org.apache.flink.runtime.metrics.MetricRegistryConfiguration; import org.apache.flink.runtime.taskmanager.NetworkEnvironmentConfiguration; import org.apache.flink.runtime.util.EnvironmentInformation; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.net.InetAddress; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.powermock.api.mockito.PowerMockito.when; /** * Unit test for {@link TaskManagerServices}. */ @RunWith(PowerMockRunner.class) @PrepareForTest(EnvironmentInformation.class) public class TaskManagerServicesTest { /** * Test for {@link TaskManagerServices#calculateNetworkBufferMemory(long, Configuration)} using old * configurations via {@link TaskManagerOptions#NETWORK_NUM_BUFFERS}. */ @SuppressWarnings("deprecation") @Test public void calculateNetworkBufOld() throws Exception { Configuration config = new Configuration(); config.setInteger(TaskManagerOptions.NETWORK_NUM_BUFFERS, 1); // note: actual network buffer memory size is independent of the totalJavaMemorySize assertEquals(TaskManagerOptions.MEMORY_SEGMENT_SIZE.defaultValue().longValue(), TaskManagerServices.calculateNetworkBufferMemory(10L << 20, config)); assertEquals(TaskManagerOptions.MEMORY_SEGMENT_SIZE.defaultValue().longValue(), TaskManagerServices.calculateNetworkBufferMemory(64L << 20, config)); // test integer overflow in the memory size int numBuffers = (int) ((2L << 32) / TaskManagerOptions.MEMORY_SEGMENT_SIZE.defaultValue()); // 2^33 config.setInteger(TaskManagerOptions.NETWORK_NUM_BUFFERS, numBuffers); assertEquals(2L << 32, TaskManagerServices.calculateNetworkBufferMemory(2L << 33, config)); } /** * Test for {@link TaskManagerServices#calculateNetworkBufferMemory(long, Configuration)} using new * configurations via {@link TaskManagerOptions#NETWORK_BUFFERS_MEMORY_FRACTION}, * {@link TaskManagerOptions#NETWORK_BUFFERS_MEMORY_MIN} and * {@link TaskManagerOptions#NETWORK_BUFFERS_MEMORY_MAX}. */ @Test public void calculateNetworkBufNew() throws Exception { Configuration config = new Configuration(); // (1) defaults final Float defaultFrac = TaskManagerOptions.NETWORK_BUFFERS_MEMORY_FRACTION.defaultValue(); final Long defaultMin = TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN.defaultValue(); final Long defaultMax = TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MAX.defaultValue(); assertEquals(enforceBounds((long) (defaultFrac * (10L << 20)), defaultMin, defaultMax), TaskManagerServices.calculateNetworkBufferMemory((64L << 20 + 1), config)); assertEquals(enforceBounds((long) (defaultFrac * (10L << 30)), defaultMin, defaultMax), TaskManagerServices.calculateNetworkBufferMemory((10L << 30), config)); calculateNetworkBufNew(config); } /** * Helper to test {@link TaskManagerServices#calculateNetworkBufferMemory(long, Configuration)} with the * new configuration parameters. * * @param config configuration object */ private static void calculateNetworkBufNew(final Configuration config) { // (2) fixed size memory config.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN, 1L << 20); // 1MB config.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MAX, 1L << 20); // 1MB // note: actual network buffer memory size is independent of the totalJavaMemorySize assertEquals(1 << 20, TaskManagerServices.calculateNetworkBufferMemory(10L << 20, config)); assertEquals(1 << 20, TaskManagerServices.calculateNetworkBufferMemory(64L << 20, config)); assertEquals(1 << 20, TaskManagerServices.calculateNetworkBufferMemory(1L << 30, config)); // (3) random fraction, min, and max values Random ran = new Random(); for (int i = 0; i < 1_000; ++i){ float frac = Math.max(ran.nextFloat(), Float.MIN_VALUE); config.setFloat(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_FRACTION, frac); long min = Math.max(TaskManagerOptions.MEMORY_SEGMENT_SIZE.defaultValue(), ran.nextLong()); config.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN, min); long max = Math.max(min, ran.nextLong()); config.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MAX, max); long javaMem = Math.max(max + 1, ran.nextLong()); final long networkBufMem = TaskManagerServices.calculateNetworkBufferMemory(javaMem, config); assertTrue("Lower bound not met with configuration: " + config.toString(), networkBufMem >= min); assertTrue("Upper bound not met with configuration: " + config.toString(), networkBufMem <= max); if (networkBufMem > min && networkBufMem < max) { assertEquals( "Wrong network buffer memory size with configuration: " + config.toString(), (long) (javaMem * frac), networkBufMem); } } } /** * Test for {@link TaskManagerServices#calculateNetworkBufferMemory(long, Configuration)} using mixed * old/new configurations. */ @SuppressWarnings("deprecation") @Test public void calculateNetworkBufMixed() throws Exception { Configuration config = new Configuration(); config.setInteger(TaskManagerOptions.NETWORK_NUM_BUFFERS, 1); final Float defaultFrac = TaskManagerOptions.NETWORK_BUFFERS_MEMORY_FRACTION.defaultValue(); final Long defaultMin = TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN.defaultValue(); final Long defaultMax = TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MAX.defaultValue(); // old + 1 new parameter = new: Configuration config1 = config.clone(); config1.setFloat(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_FRACTION, 0.1f); assertEquals(enforceBounds((long) (0.1f * (10L << 20)), defaultMin, defaultMax), TaskManagerServices.calculateNetworkBufferMemory((64L << 20 + 1), config1)); assertEquals(enforceBounds((long) (0.1f * (10L << 30)), defaultMin, defaultMax), TaskManagerServices.calculateNetworkBufferMemory((10L << 30), config1)); config1 = config.clone(); long newMin = TaskManagerOptions.MEMORY_SEGMENT_SIZE.defaultValue(); // smallest value possible config1.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN, newMin); assertEquals(enforceBounds((long) (defaultFrac * (10L << 20)), newMin, defaultMax), TaskManagerServices.calculateNetworkBufferMemory((10L << 20), config1)); assertEquals(enforceBounds((long) (defaultFrac * (10L << 30)), newMin, defaultMax), TaskManagerServices.calculateNetworkBufferMemory((10L << 30), config1)); config1 = config.clone(); long newMax = Math.max(64L << 20 + 1, TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN.defaultValue()); config1.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MAX, newMax); assertEquals(enforceBounds((long) (defaultFrac * (10L << 20)), defaultMin, newMax), TaskManagerServices.calculateNetworkBufferMemory((64L << 20 + 1), config1)); assertEquals(enforceBounds((long) (defaultFrac * (10L << 30)), defaultMin, newMax), TaskManagerServices.calculateNetworkBufferMemory((10L << 30), config1)); assertTrue(TaskManagerServicesConfiguration.hasNewNetworkBufConf(config1)); // old + any new parameter = new: calculateNetworkBufNew(config); } /** * Returns the value or the lower/upper bound in case the value is less/greater than the lower/upper bound, respectively. * * @param value value to inspec * @param lower lower bound * @param upper upper bound * * @return <tt>min(upper, max(lower, value))</tt> */ private static long enforceBounds(final long value, final long lower, final long upper) { return Math.min(upper, Math.max(lower, value)); } /** * Test for {@link TaskManagerServices#calculateNetworkBufferMemory(TaskManagerServicesConfiguration)} * using the same (manual) test cases as in {@link #calculateHeapSizeMB()}. */ @Test public void calculateNetworkBufFromHeapSize() throws Exception { PowerMockito.mockStatic(EnvironmentInformation.class); // some defaults: when(EnvironmentInformation.getSizeOfFreeHeapMemoryWithDefrag()).thenReturn(1000L << 20); // 1000MB when(EnvironmentInformation.getMaxJvmHeapMemory()).thenReturn(1000L << 20); // 1000MB TaskManagerServicesConfiguration tmConfig; tmConfig = getTmConfig(TaskManagerOptions.MANAGED_MEMORY_SIZE.defaultValue(), TaskManagerOptions.MANAGED_MEMORY_FRACTION.defaultValue(), 0.1f, 60L << 20, 1L << 30, MemoryType.HEAP); when(EnvironmentInformation.getSizeOfFreeHeapMemoryWithDefrag()).thenReturn(1000L << 20); // 1000MB assertEquals(100L << 20, TaskManagerServices.calculateNetworkBufferMemory(tmConfig)); tmConfig = getTmConfig(10, TaskManagerOptions.MANAGED_MEMORY_FRACTION.defaultValue(), 0.1f, 60L << 20, 1L << 30, MemoryType.OFF_HEAP); when(EnvironmentInformation.getMaxJvmHeapMemory()).thenReturn(890L << 20); // 890MB assertEquals((100L << 20) + 1 /* one too many due to floating point imprecision */, TaskManagerServices.calculateNetworkBufferMemory(tmConfig)); tmConfig = getTmConfig(-1, 0.1f, 0.1f, 60L << 20, 1L << 30, MemoryType.OFF_HEAP); when(EnvironmentInformation.getMaxJvmHeapMemory()).thenReturn(810L << 20); // 810MB assertEquals((100L << 20) + 1 /* one too many due to floating point imprecision */, TaskManagerServices.calculateNetworkBufferMemory(tmConfig)); } /** * Returns a task manager services configuration for the tests * * @param managedMemory see {@link TaskManagerOptions#MANAGED_MEMORY_SIZE} * @param managedMemoryFraction see {@link TaskManagerOptions#MANAGED_MEMORY_FRACTION} * @param networkBufFraction see {@link TaskManagerOptions#NETWORK_BUFFERS_MEMORY_FRACTION} * @param networkBufMin see {@link TaskManagerOptions#NETWORK_BUFFERS_MEMORY_MIN} * @param networkBufMax see {@link TaskManagerOptions#NETWORK_BUFFERS_MEMORY_MAX} * @param memType on-heap or off-heap * * @return configuration object */ private static TaskManagerServicesConfiguration getTmConfig( final long managedMemory, final float managedMemoryFraction, float networkBufFraction, long networkBufMin, long networkBufMax, final MemoryType memType) { final NetworkEnvironmentConfiguration networkConfig = new NetworkEnvironmentConfiguration( networkBufFraction, networkBufMin, networkBufMax, TaskManagerOptions.MEMORY_SEGMENT_SIZE.defaultValue(), memType, null, TaskManagerOptions.NETWORK_REQUEST_BACKOFF_INITIAL.defaultValue(), TaskManagerOptions.NETWORK_REQUEST_BACKOFF_MAX.defaultValue(), TaskManagerOptions.NETWORK_BUFFERS_PER_CHANNEL.defaultValue(), TaskManagerOptions.NETWORK_EXTRA_BUFFERS_PER_GATE.defaultValue(), null); return new TaskManagerServicesConfiguration( mock(InetAddress.class), new String[] {}, networkConfig, QueryableStateConfiguration.disabled(), 1, managedMemory, false, managedMemoryFraction, mock(MetricRegistryConfiguration.class), 0); } /** * Test for {@link TaskManagerServices#calculateHeapSizeMB(long, Configuration)} with some * manually calculated scenarios. */ @Test public void calculateHeapSizeMB() throws Exception { Configuration config = new Configuration(); config.setFloat(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_FRACTION, 0.1f); config.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MIN, 64L << 20); // 64MB config.setLong(TaskManagerOptions.NETWORK_BUFFERS_MEMORY_MAX, 1L << 30); // 1GB config.setBoolean(TaskManagerOptions.MEMORY_OFF_HEAP, false); assertEquals(1000, TaskManagerServices.calculateHeapSizeMB(1000, config)); config.setBoolean(TaskManagerOptions.MEMORY_OFF_HEAP, true); config.setLong(TaskManagerOptions.MANAGED_MEMORY_SIZE, 10); // 10MB assertEquals(890, TaskManagerServices.calculateHeapSizeMB(1000, config)); config.setLong(TaskManagerOptions.MANAGED_MEMORY_SIZE, -1); // use fraction of given memory config.setFloat(TaskManagerOptions.MANAGED_MEMORY_FRACTION, 0.1f); // 10% assertEquals(810, TaskManagerServices.calculateHeapSizeMB(1000, config)); } }