diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt
index 8283d48d6a..a5b77545d8 100644
--- a/hadoop-yarn-project/CHANGES.txt
+++ b/hadoop-yarn-project/CHANGES.txt
@@ -145,6 +145,9 @@ Release 2.6.0 - UNRELEASED
YARN-2388. Fixed TestTimelineWebServices failure due to HADOOP-10791. (zjshen)
+ YARN-2008. Fixed CapacityScheduler to calculate headroom based on max available
+ capacity instead of configured max capacity. (Craig Welch via jianhe)
+
Release 2.5.0 - UNRELEASED
INCOMPATIBLE CHANGES
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DefaultResourceCalculator.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DefaultResourceCalculator.java
index 294e6215ef..c2fc1f0e73 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DefaultResourceCalculator.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DefaultResourceCalculator.java
@@ -42,6 +42,13 @@ public float divide(Resource unused,
Resource numerator, Resource denominator) {
return ratio(numerator, denominator);
}
+
+ public boolean isInvalidDivisor(Resource r) {
+ if (r.getMemory() == 0.0f) {
+ return true;
+ }
+ return false;
+ }
@Override
public float ratio(Resource a, Resource b) {
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DominantResourceCalculator.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DominantResourceCalculator.java
index d0f5833123..6f5b40eebf 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DominantResourceCalculator.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/DominantResourceCalculator.java
@@ -109,6 +109,14 @@ public float divide(Resource clusterResource,
getResourceAsValue(clusterResource, numerator, true) /
getResourceAsValue(clusterResource, denominator, true);
}
+
+ @Override
+ public boolean isInvalidDivisor(Resource r) {
+ if (r.getMemory() == 0.0f || r.getVirtualCores() == 0.0f) {
+ return true;
+ }
+ return false;
+ }
@Override
public float ratio(Resource a, Resource b) {
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceCalculator.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceCalculator.java
index 490cd38c14..cb076997d2 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceCalculator.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/ResourceCalculator.java
@@ -149,6 +149,15 @@ public abstract Resource normalize(Resource r, Resource minimumResource,
public abstract float divide(
Resource clusterResource, Resource numerator, Resource denominator);
+ /**
+ * Determine if a resource is not suitable for use as a divisor
+ * (will result in divide by 0, etc)
+ *
+ * @param r resource
+ * @return true if divisor is invalid (should not be used), false else
+ */
+ public abstract boolean isInvalidDivisor(Resource r);
+
/**
* Ratio of resource a
to resource b
.
*
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/Resources.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/Resources.java
index 800fa34e57..077c962883 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/Resources.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/resource/Resources.java
@@ -184,6 +184,11 @@ public static Resource roundDown(
return calculator.roundDown(lhs, factor);
}
+ public static boolean isInvalidDivisor(
+ ResourceCalculator resourceCalculator, Resource divisor) {
+ return resourceCalculator.isInvalidDivisor(divisor);
+ }
+
public static float ratio(
ResourceCalculator resourceCalculator, Resource lhs, Resource rhs) {
return resourceCalculator.ratio(lhs, rhs);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CSQueueUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CSQueueUtils.java
index 1dd55862b9..737062bbcd 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CSQueueUtils.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CSQueueUtils.java
@@ -17,6 +17,9 @@
*/
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.server.utils.Lock;
import org.apache.hadoop.yarn.util.resource.ResourceCalculator;
@@ -24,6 +27,8 @@
class CSQueueUtils {
+ private static final Log LOG = LogFactory.getLog(CSQueueUtils.class);
+
final static float EPSILON = 0.0001f;
public static void checkMaxCapacity(String queueName,
@@ -113,4 +118,52 @@ public static void updateQueueStatistics(
)
);
}
+
+ public static float getAbsoluteMaxAvailCapacity(
+ ResourceCalculator resourceCalculator, Resource clusterResource, CSQueue queue) {
+ CSQueue parent = queue.getParent();
+ if (parent == null) {
+ return queue.getAbsoluteMaximumCapacity();
+ }
+
+ //Get my parent's max avail, needed to determine my own
+ float parentMaxAvail = getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, parent);
+ //...and as a resource
+ Resource parentResource = Resources.multiply(clusterResource, parentMaxAvail);
+
+ //check for no resources parent before dividing, if so, max avail is none
+ if (Resources.isInvalidDivisor(resourceCalculator, parentResource)) {
+ return 0.0f;
+ }
+ //sibling used is parent used - my used...
+ float siblingUsedCapacity = Resources.ratio(
+ resourceCalculator,
+ Resources.subtract(parent.getUsedResources(), queue.getUsedResources()),
+ parentResource);
+ //my max avail is the lesser of my max capacity and what is unused from my parent
+ //by my siblings (if they are beyond their base capacity)
+ float maxAvail = Math.min(
+ queue.getMaximumCapacity(),
+ 1.0f - siblingUsedCapacity);
+ //and, mutiply by parent to get absolute (cluster relative) value
+ float absoluteMaxAvail = maxAvail * parentMaxAvail;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("qpath " + queue.getQueuePath());
+ LOG.debug("parentMaxAvail " + parentMaxAvail);
+ LOG.debug("siblingUsedCapacity " + siblingUsedCapacity);
+ LOG.debug("getAbsoluteMaximumCapacity " + queue.getAbsoluteMaximumCapacity());
+ LOG.debug("maxAvail " + maxAvail);
+ LOG.debug("absoluteMaxAvail " + absoluteMaxAvail);
+ }
+
+ if (absoluteMaxAvail < 0.0f) {
+ absoluteMaxAvail = 0.0f;
+ } else if (absoluteMaxAvail > 1.0f) {
+ absoluteMaxAvail = 1.0f;
+ }
+
+ return absoluteMaxAvail;
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java
index 65938aab8d..4fd8b49057 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/LeafQueue.java
@@ -976,13 +976,18 @@ private Resource computeUserLimitAndSetHeadroom(
Resource userLimit = // User limit
computeUserLimit(application, clusterResource, required);
-
+
+ //Max avail capacity needs to take into account usage by ancestor-siblings
+ //which are greater than their base capacity, so we are interested in "max avail"
+ //capacity
+ float absoluteMaxAvailCapacity = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, this);
Resource queueMaxCap = // Queue Max-Capacity
Resources.multiplyAndNormalizeDown(
resourceCalculator,
clusterResource,
- absoluteMaxCapacity,
+ absoluteMaxAvailCapacity,
minimumAllocation);
Resource userConsumed = getUser(user).getConsumedResources();
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCSQueueUtils.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCSQueueUtils.java
new file mode 100644
index 0000000000..7260afd9bc
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCSQueueUtils.java
@@ -0,0 +1,262 @@
+/**
+ * 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.hadoop.yarn.server.resourcemanager.scheduler.capacity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator;
+import org.apache.hadoop.yarn.util.resource.DominantResourceCalculator;
+import org.apache.hadoop.yarn.util.resource.ResourceCalculator;
+import org.apache.hadoop.yarn.util.resource.Resources;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class TestCSQueueUtils {
+
+ private static final Log LOG = LogFactory.getLog(TestCSQueueUtils.class);
+
+ final static int GB = 1024;
+
+ @Test
+ public void testAbsoluteMaxAvailCapacityInvalidDivisor() throws Exception {
+ runInvalidDivisorTest(false);
+ runInvalidDivisorTest(true);
+ }
+
+ public void runInvalidDivisorTest(boolean useDominant) throws Exception {
+
+ ResourceCalculator resourceCalculator;
+ Resource clusterResource;
+ if (useDominant) {
+ resourceCalculator = new DominantResourceCalculator();
+ clusterResource = Resources.createResource(10, 0);
+ } else {
+ resourceCalculator = new DefaultResourceCalculator();
+ clusterResource = Resources.createResource(0, 99);
+ }
+
+ YarnConfiguration conf = new YarnConfiguration();
+ CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration();
+
+ CapacitySchedulerContext csContext = mock(CapacitySchedulerContext.class);
+ when(csContext.getConf()).thenReturn(conf);
+ when(csContext.getConfiguration()).thenReturn(csConf);
+ when(csContext.getClusterResource()).thenReturn(clusterResource);
+ when(csContext.getResourceCalculator()).thenReturn(resourceCalculator);
+ when(csContext.getMinimumResourceCapability()).
+ thenReturn(Resources.createResource(GB, 1));
+ when(csContext.getMaximumResourceCapability()).
+ thenReturn(Resources.createResource(0, 0));
+
+ final String L1Q1 = "L1Q1";
+ csConf.setQueues(CapacitySchedulerConfiguration.ROOT, new String[] {L1Q1});
+
+ final String L1Q1P = CapacitySchedulerConfiguration.ROOT + "." + L1Q1;
+ csConf.setCapacity(L1Q1P, 90);
+ csConf.setMaximumCapacity(L1Q1P, 90);
+
+ ParentQueue root = new ParentQueue(csContext,
+ CapacitySchedulerConfiguration.ROOT, null, null);
+ LeafQueue l1q1 = new LeafQueue(csContext, L1Q1, root, null);
+
+ LOG.info("t1 root " + CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, root));
+
+ LOG.info("t1 l1q1 " + CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l1q1));
+
+ assertEquals(0.0f, CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l1q1), 0.000001f);
+
+ }
+
+ @Test
+ public void testAbsoluteMaxAvailCapacityNoUse() throws Exception {
+
+ ResourceCalculator resourceCalculator = new DefaultResourceCalculator();
+ Resource clusterResource = Resources.createResource(100 * 16 * GB, 100 * 32);
+
+ YarnConfiguration conf = new YarnConfiguration();
+ CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration();
+
+ CapacitySchedulerContext csContext = mock(CapacitySchedulerContext.class);
+ when(csContext.getConf()).thenReturn(conf);
+ when(csContext.getConfiguration()).thenReturn(csConf);
+ when(csContext.getClusterResource()).thenReturn(clusterResource);
+ when(csContext.getResourceCalculator()).thenReturn(resourceCalculator);
+ when(csContext.getMinimumResourceCapability()).
+ thenReturn(Resources.createResource(GB, 1));
+ when(csContext.getMaximumResourceCapability()).
+ thenReturn(Resources.createResource(16*GB, 32));
+
+ final String L1Q1 = "L1Q1";
+ csConf.setQueues(CapacitySchedulerConfiguration.ROOT, new String[] {L1Q1});
+
+ final String L1Q1P = CapacitySchedulerConfiguration.ROOT + "." + L1Q1;
+ csConf.setCapacity(L1Q1P, 90);
+ csConf.setMaximumCapacity(L1Q1P, 90);
+
+ ParentQueue root = new ParentQueue(csContext,
+ CapacitySchedulerConfiguration.ROOT, null, null);
+ LeafQueue l1q1 = new LeafQueue(csContext, L1Q1, root, null);
+
+ LOG.info("t1 root " + CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, root));
+
+ LOG.info("t1 l1q1 " + CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l1q1));
+
+ assertEquals(1.0f, CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, root), 0.000001f);
+
+ assertEquals(0.9f, CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l1q1), 0.000001f);
+
+ }
+
+ @Test
+ public void testAbsoluteMaxAvailCapacityWithUse() throws Exception {
+
+ ResourceCalculator resourceCalculator = new DefaultResourceCalculator();
+ Resource clusterResource = Resources.createResource(100 * 16 * GB, 100 * 32);
+
+ YarnConfiguration conf = new YarnConfiguration();
+ CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration();
+
+ CapacitySchedulerContext csContext = mock(CapacitySchedulerContext.class);
+ when(csContext.getConf()).thenReturn(conf);
+ when(csContext.getConfiguration()).thenReturn(csConf);
+ when(csContext.getClusterResource()).thenReturn(clusterResource);
+ when(csContext.getResourceCalculator()).thenReturn(resourceCalculator);
+ when(csContext.getMinimumResourceCapability()).
+ thenReturn(Resources.createResource(GB, 1));
+ when(csContext.getMaximumResourceCapability()).
+ thenReturn(Resources.createResource(16*GB, 32));
+
+ final String L1Q1 = "L1Q1";
+ final String L1Q2 = "L1Q2";
+ final String L2Q1 = "L2Q1";
+ final String L2Q2 = "L2Q2";
+ csConf.setQueues(CapacitySchedulerConfiguration.ROOT, new String[] {L1Q1, L1Q2,
+ L2Q1, L2Q2});
+
+ final String L1Q1P = CapacitySchedulerConfiguration.ROOT + "." + L1Q1;
+ csConf.setCapacity(L1Q1P, 80);
+ csConf.setMaximumCapacity(L1Q1P, 80);
+
+ final String L1Q2P = CapacitySchedulerConfiguration.ROOT + "." + L1Q2;
+ csConf.setCapacity(L1Q2P, 20);
+ csConf.setMaximumCapacity(L1Q2P, 100);
+
+ final String L2Q1P = L1Q1P + "." + L2Q1;
+ csConf.setCapacity(L2Q1P, 50);
+ csConf.setMaximumCapacity(L2Q1P, 50);
+
+ final String L2Q2P = L1Q1P + "." + L2Q2;
+ csConf.setCapacity(L2Q2P, 50);
+ csConf.setMaximumCapacity(L2Q2P, 50);
+
+ float result;
+
+ ParentQueue root = new ParentQueue(csContext,
+ CapacitySchedulerConfiguration.ROOT, null, null);
+
+ LeafQueue l1q1 = new LeafQueue(csContext, L1Q1, root, null);
+ LeafQueue l1q2 = new LeafQueue(csContext, L1Q2, root, null);
+ LeafQueue l2q2 = new LeafQueue(csContext, L2Q2, l1q1, null);
+ LeafQueue l2q1 = new LeafQueue(csContext, L2Q1, l1q1, null);
+
+ //no usage, all based on maxCapacity (prior behavior)
+ result = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l2q2);
+ assertEquals( 0.4f, result, 0.000001f);
+ LOG.info("t2 l2q2 " + result);
+
+ //some usage, but below the base capacity
+ Resources.addTo(root.getUsedResources(), Resources.multiply(clusterResource, 0.1f));
+ Resources.addTo(l1q2.getUsedResources(), Resources.multiply(clusterResource, 0.1f));
+ result = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l2q2);
+ assertEquals( 0.4f, result, 0.000001f);
+ LOG.info("t2 l2q2 " + result);
+
+ //usage gt base on parent sibling
+ Resources.addTo(root.getUsedResources(), Resources.multiply(clusterResource, 0.3f));
+ Resources.addTo(l1q2.getUsedResources(), Resources.multiply(clusterResource, 0.3f));
+ result = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l2q2);
+ assertEquals( 0.3f, result, 0.000001f);
+ LOG.info("t2 l2q2 " + result);
+
+ //same as last, but with usage also on direct parent
+ Resources.addTo(root.getUsedResources(), Resources.multiply(clusterResource, 0.1f));
+ Resources.addTo(l1q1.getUsedResources(), Resources.multiply(clusterResource, 0.1f));
+ result = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l2q2);
+ assertEquals( 0.3f, result, 0.000001f);
+ LOG.info("t2 l2q2 " + result);
+
+ //add to direct sibling, below the threshold of effect at present
+ Resources.addTo(root.getUsedResources(), Resources.multiply(clusterResource, 0.2f));
+ Resources.addTo(l1q1.getUsedResources(), Resources.multiply(clusterResource, 0.2f));
+ Resources.addTo(l2q1.getUsedResources(), Resources.multiply(clusterResource, 0.2f));
+ result = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l2q2);
+ assertEquals( 0.3f, result, 0.000001f);
+ LOG.info("t2 l2q2 " + result);
+
+ //add to direct sibling, now above the threshold of effect
+ //(it's cumulative with prior tests)
+ Resources.addTo(root.getUsedResources(), Resources.multiply(clusterResource, 0.2f));
+ Resources.addTo(l1q1.getUsedResources(), Resources.multiply(clusterResource, 0.2f));
+ Resources.addTo(l2q1.getUsedResources(), Resources.multiply(clusterResource, 0.2f));
+ result = CSQueueUtils.getAbsoluteMaxAvailCapacity(
+ resourceCalculator, clusterResource, l2q2);
+ assertEquals( 0.1f, result, 0.000001f);
+ LOG.info("t2 l2q2 " + result);
+
+
+ }
+
+}