diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java index 96f348c68..a20071df6 100644 --- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java +++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java @@ -567,7 +567,6 @@ public class ConstraintLayout extends ViewGroup { private static final boolean USE_CONSTRAINTS_HELPER = true; private static final boolean DEBUG = LinearSystem.FULL_DEBUG; private static final boolean DEBUG_DRAW_CONSTRAINTS = false; - private static final boolean MEASURE = false; private static final boolean OPTIMIZE_HEIGHT_CHANGE = false; SparseArray mChildrenByIds = new SparseArray<>(); @@ -741,10 +740,11 @@ public final void measure(ConstraintWidget widget, return; } - long startMeasure; + long startMeasure = 0; long endMeasure; - if (MEASURE) { + if (mMetrics != null) { + mMetrics.mNumberOfMeasures++; startMeasure = System.nanoTime(); } @@ -1008,11 +1008,9 @@ && isSimilarSpec(widget.getLastVerticalMeasureSpec(), measure.measuredHeight = height; measure.measuredHasBaseline = hasBaseline; measure.measuredBaseline = baseline; - if (MEASURE) { + if (mMetrics != null) { endMeasure = System.nanoTime(); - if (mMetrics != null) { - mMetrics.measuresWidgetsDuration += (endMeasure - startMeasure); - } + mMetrics.measuresWidgetsDuration += (endMeasure - startMeasure); } } @@ -1736,6 +1734,7 @@ protected void resolveSystem(ConstraintWidgetContainer layout, heightSize -= paddingHeight; setSelfDimensionBehaviour(layout, widthMode, widthSize, heightMode, heightSize); + layout.measure(optimizationLevel, widthMode, widthSize, heightMode, heightSize, mLastMeasureWidth, mLastMeasureHeight, paddingX, paddingY); } @@ -1788,8 +1787,10 @@ protected void resolveMeasuredDimension(int widthMeasureSpec, @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { long time = 0; - if (DEBUG) { - time = System.currentTimeMillis(); + if (mMetrics != null) { + time = System.nanoTime(); + mMetrics.mChildCount = getChildCount(); + mMetrics.mMeasureCalls++; } mDirtyHierarchy |= dynamicUpdateConstraints(widthMeasureSpec, heightMeasureSpec); @@ -1827,6 +1828,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mLayoutWidget.getWidth(), mLayoutWidget.getHeight(), mLayoutWidget.isWidthMeasuredTooSmall(), mLayoutWidget.isHeightMeasuredTooSmall()); + if (mMetrics != null) { + mMetrics.mMeasureDuration += System.nanoTime() - time; + } return; } if (OPTIMIZE_HEIGHT_CHANGE @@ -1847,6 +1851,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mLayoutWidget.getWidth(), mLayoutWidget.getHeight(), mLayoutWidget.isWidthMeasuredTooSmall(), mLayoutWidget.isHeightMeasuredTooSmall()); + if (mMetrics != null) { + mMetrics.mMeasureDuration += System.nanoTime() - time; + } return; } } @@ -1869,14 +1876,18 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mLayoutWidget.updateHierarchy(); } } + mLayoutWidget.fillMetrics(mMetrics); resolveSystem(mLayoutWidget, mOptimizationLevel, widthMeasureSpec, heightMeasureSpec); resolveMeasuredDimension(widthMeasureSpec, heightMeasureSpec, mLayoutWidget.getWidth(), mLayoutWidget.getHeight(), mLayoutWidget.isWidthMeasuredTooSmall(), mLayoutWidget.isHeightMeasuredTooSmall()); + if (mMetrics != null) { + mMetrics.mMeasureDuration += System.nanoTime() - time; + } if (DEBUG) { - time = System.currentTimeMillis() - time; + time = System.nanoTime() - time; System.out.println(mLayoutWidget.getDebugName() + " (" + getChildCount() + ") DONE onMeasure width: " + MeasureSpec.toString(widthMeasureSpec) + " height: " + MeasureSpec.toString(heightMeasureSpec) + " => " @@ -2008,6 +2019,9 @@ public void setState(int id, int screenWidth, int screenHeight) { */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (mMetrics != null) { + mMetrics.mNumberOfLayouts++; + } if (DEBUG) { System.out.println(mLayoutWidget.getDebugName() + " onLayout changed: " + changed + " left: " + left + " top: " + top diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutPerformance.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutPerformance.java deleted file mode 100644 index 32a50ac04..000000000 --- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutPerformance.java +++ /dev/null @@ -1,2 +0,0 @@ -package androidx.constraintlayout.widget;public class ConstraintLayoutPerformance { -} diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java new file mode 100644 index 000000000..e684b7c68 --- /dev/null +++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayoutStatistics.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * 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. + */ + +package androidx.constraintlayout.widget; + +import android.annotation.SuppressLint; +import android.util.Log; + +import androidx.constraintlayout.core.Metrics; + +import java.text.DecimalFormat; +import java.util.ArrayList; + +/** + * This provide metrics of the complexity of the layout that is being solved. + * The intent is for developers using the too to track the evolution of their UI + * Typically the developer will monitor the computations on every callback of + * mConstraintLayout.addOnLayoutChangeListener(this::callback); + * + */ +public class ConstraintLayoutStatistics { + public final static int NUMBER_OF_LAYOUTS = 1; + public final static int NUMBER_OF_ON_MEASURES= 2; + public final static int NUMBER_OF_CHILD_VIEWS= 3; + public final static int NUMBER_OF_CHILD_MEASURES= 4; + public final static int DURATION_OF_CHILD_MEASURES= 5; + public final static int DURATION_OF_MEASURES = 6; + public final static int DURATION_OF_LAYOUT = 7; + public final static int NUMBER_OF_VARIABLES = 8; + public final static int NUMBER_OF_EQUATIONS = 9; + public final static int NUMBER_OF_SIMPLE_EQUATIONS = 10; + + private final Metrics mMetrics = new Metrics(); + ConstraintLayout mConstraintLayout; + private static int MAX_WORD = 25; + private static final String WORD_PAD = new String(new char[MAX_WORD]).replace('\0', ' '); + + /** + * Measure performance information about ConstraintLayout + * + * @param constraintLayout + */ + public ConstraintLayoutStatistics(ConstraintLayout constraintLayout) { + attach(constraintLayout); + } + + /** + * Copy a layout Stats useful for comparing two stats + * @param copy + */ + public ConstraintLayoutStatistics(ConstraintLayoutStatistics copy) { + mMetrics.copy(copy.mMetrics); + } + + + /** + * Attach to a ConstraintLayout to gather statistics on its layout performance + * @param constraintLayout + */ + public void attach(ConstraintLayout constraintLayout) { + constraintLayout.fillMetrics(mMetrics); + mConstraintLayout = constraintLayout; + } + + /** + * Detach from a ConstraintLayout + */ + public void detach() { + if (mConstraintLayout != null) { + mConstraintLayout.fillMetrics(null); + } + } + + /** + * Clear the current metrics + */ + public void reset() { + mMetrics.reset(); + } + + /** + * Create a copy of the statistics + * @return a copy + */ + public ConstraintLayoutStatistics clone() { + return new ConstraintLayoutStatistics(this); + } + + /** + * Format a float value outputting a string of fixed length + * @param df format to use + * @param val + * @param length + * @return + */ + private String fmt(DecimalFormat df, float val, int length) { + String s = new String(new char[length]).replace('\0', ' '); + s = (s + df.format(val)); + return s.substring(s.length() - length); + } + + /** + * Log a summary of the statistics + * @param tag + */ + public void logSummary(String tag) { + log(tag); + } + + @SuppressLint({"LogConditional"}) + private void log(String tag) { + String value; + StackTraceElement s = new Throwable().getStackTrace()[2]; + + Log.v(tag, "CL Perf: -------- Performance .(" + s.getFileName() + ":" + s.getLineNumber() + ") ------ "); + + DecimalFormat df = new DecimalFormat("###.000"); + + Log.v(tag, log(df, DURATION_OF_CHILD_MEASURES)); + Log.v(tag, log(df, DURATION_OF_LAYOUT)); + Log.v(tag, log(df, DURATION_OF_MEASURES)); + Log.v(tag, log(NUMBER_OF_LAYOUTS)); + Log.v(tag, log( NUMBER_OF_ON_MEASURES)); + Log.v(tag, log(NUMBER_OF_CHILD_VIEWS)); + Log.v(tag, log(NUMBER_OF_CHILD_MEASURES)); + Log.v(tag, log(NUMBER_OF_VARIABLES)); + Log.v(tag, log(NUMBER_OF_EQUATIONS)); + Log.v(tag, log( NUMBER_OF_SIMPLE_EQUATIONS)); + } + + /** + * Generate a formatted String for the parameter formatting as a float + * @param df + * @param param + * @return + */ + private String log(DecimalFormat df, int param) { + String value = fmt(df, getValue(param) * 1E-6f, 7); + + String title = geName(param); + title = WORD_PAD + title; + title = title.substring(title.length() - MAX_WORD); + title += " = "; + return "CL Perf: " + title + value; + } + + /** + * Generate a formatted String for the parameter + * @param param + * @return + */ + private String log(int param) { + String value = Long.toString(this.getValue(param)); + String title = geName(param); + title = WORD_PAD + title; + title = title.substring(title.length() - MAX_WORD); + title += " = "; + return "CL Perf: " + title + value; + } + + /** + * Generate a float formatted String for the parameter comparing current value with value in relative + * @param df Format the float using this + * @param relative compare against + * @param param the parameter to compare + * @return + */ + private String compare(DecimalFormat df, ConstraintLayoutStatistics relative, int param) { + String value = fmt(df, getValue(param) * 1E-6f, 7); + value += " -> " + fmt(df, relative.getValue(param) * 1E-6f, 7) + "ms"; + String title = geName(param); + title = WORD_PAD + title; + title = title.substring(title.length() - MAX_WORD); + title += " = "; + return "CL Perf: " + title + value; + } + + /** + * Generate a formatted String for the parameter comparing current value with value in relative + * @param relative compare against + * @param param the parameter to compare + * @return + */ + private String compare(ConstraintLayoutStatistics relative, int param) { + String value = this.getValue(param) + " -> " + relative.getValue(param); + String title = geName(param); + + title = WORD_PAD + title; + title = title.substring(title.length() - MAX_WORD); + title += " = "; + return "CL Perf: " + title + value; + } + + /** + * log a summary of the stats compared to another statics + * @param tag used in Log.v(tag, ...) + * @param prev the previous stats to compare to + */ + @SuppressLint("LogConditional") + public void logSummary(String tag, ConstraintLayoutStatistics prev) { + if (prev == null) { + log(tag); + return; + } + DecimalFormat df = new DecimalFormat("###.000"); + StackTraceElement s = new Throwable().getStackTrace()[1]; + + Log.v(tag, "CL Perf: -= Performance .(" + s.getFileName() + ":" + s.getLineNumber() + ") =- "); + Log.v(tag, compare(df, prev, DURATION_OF_CHILD_MEASURES)); + Log.v(tag, compare(df, prev, DURATION_OF_LAYOUT)); + Log.v(tag, compare(df, prev, DURATION_OF_MEASURES)); + Log.v(tag, compare(prev, NUMBER_OF_LAYOUTS)); + Log.v(tag, compare(prev, NUMBER_OF_ON_MEASURES)); + Log.v(tag, compare(prev, NUMBER_OF_CHILD_VIEWS)); + Log.v(tag, compare(prev, NUMBER_OF_CHILD_MEASURES)); + Log.v(tag, compare(prev, NUMBER_OF_VARIABLES)); + Log.v(tag, compare(prev, NUMBER_OF_EQUATIONS)); + Log.v(tag, compare(prev, NUMBER_OF_SIMPLE_EQUATIONS)); + } + + /** + * get the value of a statistic + * @param type + * @return + */ + public long getValue(int type) { + switch (type) { + case NUMBER_OF_LAYOUTS: + return mMetrics.mNumberOfLayouts; + case NUMBER_OF_ON_MEASURES: + return mMetrics.mMeasureCalls; + case NUMBER_OF_CHILD_VIEWS: + return mMetrics.mChildCount; + case NUMBER_OF_CHILD_MEASURES: + return mMetrics.mNumberOfMeasures; + case DURATION_OF_CHILD_MEASURES: + return mMetrics.measuresWidgetsDuration ; + case DURATION_OF_MEASURES: + return mMetrics.mMeasureDuration; + case DURATION_OF_LAYOUT: + return mMetrics.measuresLayoutDuration; + case NUMBER_OF_VARIABLES: + return mMetrics.mVariables; + case NUMBER_OF_EQUATIONS: + return mMetrics.mEquations; + case NUMBER_OF_SIMPLE_EQUATIONS: + return mMetrics.mSimpleEquations; + } + return 0; + } + + /** get a simple name for a statistic + * + * @param type type of statistic + * @return a camel case + */ + String geName(int type) { + switch (type) { + case NUMBER_OF_LAYOUTS: + return "NumberOfLayouts"; + case NUMBER_OF_ON_MEASURES: + return "MeasureCalls"; + case NUMBER_OF_CHILD_VIEWS: + return "ChildCount"; + case NUMBER_OF_CHILD_MEASURES: + return "ChildrenMeasures"; + case DURATION_OF_CHILD_MEASURES: + return "MeasuresWidgetsDuration "; + case DURATION_OF_MEASURES: + return "MeasureDuration"; + case DURATION_OF_LAYOUT: + return "MeasuresLayoutDuration"; + case NUMBER_OF_VARIABLES: + return "SolverVariables"; + case NUMBER_OF_EQUATIONS: + return "SolverEquations"; + case NUMBER_OF_SIMPLE_EQUATIONS: + return "SimpleEquations"; + } + return ""; + } + +} diff --git a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/LinearSystem.java b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/LinearSystem.java index 3b29b0ab9..309a25b05 100644 --- a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/LinearSystem.java +++ b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/LinearSystem.java @@ -31,7 +31,6 @@ public class LinearSystem { public static final boolean FULL_DEBUG = false; public static final boolean DEBUG = false; private static final boolean DO_NOT_USE = false; - public static final boolean MEASURE = false; private static final boolean DEBUG_CONSTRAINTS = FULL_DEBUG; @@ -1395,6 +1394,9 @@ public void addSynonym(SolverVariable a, SolverVariable b, int margin) { * @param strength strength used */ public ArrayRow addEquality(SolverVariable a, SolverVariable b, int margin, int strength) { + if (sMetrics != null) { + sMetrics.mSimpleEquations++; + } if (USE_BASIC_SYNONYMS && strength == SolverVariable.STRENGTH_FIXED && b.isFinalValue && a.mDefinitionId == -1) { if (DEBUG_CONSTRAINTS) { @@ -1442,6 +1444,9 @@ public ArrayRow addEquality(SolverVariable a, SolverVariable b, int margin, int * @param value the value we set */ public void addEquality(SolverVariable a, int value) { + if (sMetrics != null) { + sMetrics.mSimpleEquations++; + } if (USE_BASIC_SYNONYMS && a.mDefinitionId == -1) { if (DEBUG_CONSTRAINTS) { System.out.println("=> " + a + " = " + value + " (Synonym)"); diff --git a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/Metrics.java b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/Metrics.java index 0fb822b4e..70da2cfad 100644 --- a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/Metrics.java +++ b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/Metrics.java @@ -21,8 +21,8 @@ * Utility class to track metrics during the system resolution */ public class Metrics { - public long measuresWidgetsDuration; - public long measuresLayoutDuration; + public long measuresWidgetsDuration; // time spent in child measures in nanoseconds + public long measuresLayoutDuration; // time spent in child measures in nanoseconds public long measuredWidgets; public long measuredMatchWidgets; public long measures; @@ -49,11 +49,6 @@ public class Metrics { public long minimizeGoal; public long maxVariables; public long maxRows; - public long centerConnectionResolved; - public long matchConnectionResolved; - public long chainConnectionResolved; - public long barrierConnectionResolved; - public long oldresolvedWidgets; public long nonresolvedWidgets; public ArrayList problematicLayouts = new ArrayList<>(); public long lastTableSize; @@ -64,6 +59,15 @@ public class Metrics { public long determineGroups; public long layouts; public long grouping; + public int mNumberOfLayouts; // the number of times ConstraintLayout onLayout gets called + public int mNumberOfMeasures; // the number of times child measures gets called + public long mMeasureDuration; // time spent in measure in nanoseconds + public long mChildCount; // number of child Views of ConstraintLayout + public long mMeasureCalls; // number of time CL onMeasure is called + public long mSolverPasses; + public long mEquations; + public long mVariables; + public long mSimpleEquations; // @TODO: add description @Override @@ -77,39 +81,7 @@ public String toString() { + "graphOptimizer: " + graphOptimizer + "\n" + "widgets: " + widgets + "\n" + "graphSolved: " + graphSolved + "\n" - + "linearSolved: " + linearSolved + "\n" -/* - + "measures: " + measures + "\n" - + "additionalMeasures: " + additionalMeasures + "\n" - + "resolutions passes: " + resolutions + "\n" - + "table increases: " + tableSizeIncrease + "\n" - + "maxTableSize: " + maxTableSize + "\n" - + "maxVariables: " + maxVariables + "\n" - + "maxRows: " + maxRows + "\n\n" - + "minimize: " + minimize + "\n" - + "minimizeGoal: " + minimizeGoal + "\n" - + "constraints: " + constraints + "\n" - + "simpleconstraints: " + simpleconstraints + "\n" - + "optimize: " + optimize + "\n" - + "iterations: " + iterations + "\n" - + "pivots: " + pivots + "\n" - + "bfs: " + bfs + "\n" - + "variables: " + variables + "\n" - + "errors: " + errors + "\n" - + "slackvariables: " + slackvariables + "\n" - + "extravariables: " + extravariables + "\n" - + "fullySolved: " + fullySolved + "\n" - + "graphOptimizer: " + graphOptimizer + "\n" - + "resolvedWidgets: " + resolvedWidgets + "\n" - + "oldresolvedWidgets: " + oldresolvedWidgets + "\n" - + "nonresolvedWidgets: " + nonresolvedWidgets + "\n" - + "centerConnectionResolved: " + centerConnectionResolved + "\n" - + "matchConnectionResolved: " + matchConnectionResolved + "\n" - + "chainConnectionResolved: " + chainConnectionResolved + "\n" - + "barrierConnectionResolved: " + barrierConnectionResolved + "\n" - + "problematicsLayouts: " + problematicLayouts + "\n" - */ - ; + + "linearSolved: " + linearSolved + "\n"; } // @TODO: add description @@ -139,12 +111,65 @@ public void reset() { graphOptimizer = 0; graphSolved = 0; resolvedWidgets = 0; - oldresolvedWidgets = 0; nonresolvedWidgets = 0; - centerConnectionResolved = 0; - matchConnectionResolved = 0; - chainConnectionResolved = 0; - barrierConnectionResolved = 0; + linearSolved = 0; problematicLayouts.clear(); + mNumberOfMeasures = 0; + mNumberOfLayouts = 0; + measuresWidgetsDuration = 0; + measuresLayoutDuration = 0; + mChildCount = 0; + mMeasureDuration = 0; + mMeasureCalls = 0; + mSolverPasses = 0; + mVariables = 0; + mEquations = 0; + mSimpleEquations = 0; + } + + /** + * Copy the values from and existing Metrics class + * @param metrics + */ + public void copy(Metrics metrics) { + mVariables = metrics.mVariables; + mEquations = metrics.mEquations; + mSimpleEquations = metrics.mSimpleEquations; + mNumberOfMeasures = metrics.mNumberOfMeasures; + mNumberOfLayouts = metrics.mNumberOfLayouts; + mMeasureDuration = metrics.mMeasureDuration; + mChildCount = metrics.mChildCount; + mMeasureCalls = metrics.mMeasureCalls; + measuresWidgetsDuration = metrics.measuresWidgetsDuration; + mSolverPasses = metrics.mSolverPasses; + + measuresLayoutDuration = metrics.measuresLayoutDuration; + measures = metrics.measures; + widgets = metrics.widgets; + additionalMeasures = metrics.additionalMeasures; + resolutions = metrics.resolutions; + tableSizeIncrease = metrics.tableSizeIncrease; + maxTableSize = metrics.maxTableSize; + lastTableSize = metrics.lastTableSize; + maxVariables = metrics.maxVariables; + maxRows = metrics.maxRows; + minimize = metrics.minimize; + minimizeGoal = metrics.minimizeGoal; + constraints = metrics.constraints; + simpleconstraints = metrics.simpleconstraints; + optimize = metrics.optimize; + iterations = metrics.iterations; + pivots = metrics.pivots; + bfs = metrics.bfs; + variables = metrics.variables; + errors = metrics.errors; + slackvariables = metrics.slackvariables; + extravariables = metrics.extravariables; + fullySolved = metrics.fullySolved; + graphOptimizer = metrics.graphOptimizer; + graphSolved = metrics.graphSolved; + resolvedWidgets = metrics.resolvedWidgets; + nonresolvedWidgets = metrics.nonresolvedWidgets; } + } diff --git a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/ConstraintWidget.java b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/ConstraintWidget.java index 8fd3df49b..668d642c9 100644 --- a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/ConstraintWidget.java +++ b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/ConstraintWidget.java @@ -2865,6 +2865,11 @@ public void addToSolver(LinearSystem system, boolean optimize) { } mResolvedHorizontal = false; mResolvedVertical = false; + if (LinearSystem.sMetrics != null) { + LinearSystem.sMetrics.mEquations = system.getNumEquations(); + LinearSystem.sMetrics.mVariables = system.getNumVariables(); + } + } /** diff --git a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/analyzer/BasicMeasure.java b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/analyzer/BasicMeasure.java index 09631a618..e81d9cbe9 100644 --- a/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/analyzer/BasicMeasure.java +++ b/constraintlayout/core/src/main/java/androidx/constraintlayout/core/widgets/analyzer/BasicMeasure.java @@ -150,8 +150,8 @@ private void solveLinearSystem(ConstraintWidgetContainer layout, int pass, int w, int h) { - long startLayout; - if (LinearSystem.MEASURE) { + long startLayout = 0; + if (layout.mMetrics != null) { startLayout = System.nanoTime(); } @@ -168,8 +168,9 @@ private void solveLinearSystem(ConstraintWidgetContainer layout, } mConstraintWidgetContainer.setPass(pass); mConstraintWidgetContainer.layout(); - if (LinearSystem.MEASURE && layout.mMetrics != null) { + if (layout.mMetrics != null) { long endLayout = System.nanoTime(); + layout.mMetrics.mSolverPasses++; layout.mMetrics.measuresLayoutDuration += (endLayout - startLayout); } } @@ -283,7 +284,7 @@ public long solverMeasure(ConstraintWidgetContainer layout, if (childCount > 0) { measureChildren(layout); } - if (LinearSystem.MEASURE) { + if (layout.mMetrics != null) { layoutTime = System.nanoTime(); } @@ -445,7 +446,7 @@ public long solverMeasure(ConstraintWidgetContainer layout, } layout.setOptimizationLevel(optimizations); } - if (LinearSystem.MEASURE) { + if (layout.mMetrics != null) { layoutTime = (System.nanoTime() - layoutTime); } return layoutTime; diff --git a/projects/MotionLayoutVerification/app/src/main/AndroidManifest.xml b/projects/MotionLayoutVerification/app/src/main/AndroidManifest.xml index c27f10719..00e764d5e 100644 --- a/projects/MotionLayoutVerification/app/src/main/AndroidManifest.xml +++ b/projects/MotionLayoutVerification/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/CheckPerformanceMetric.java b/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/CheckPerformanceMetric.java new file mode 100644 index 000000000..f8c7896ea --- /dev/null +++ b/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/CheckPerformanceMetric.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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. + */ + +package android.support.constraint.app; + +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.constraintlayout.motion.widget.Debug; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.constraintlayout.widget.ConstraintLayoutStatistics; + +/** + * Test transitionToState bug + */ +public class CheckPerformanceMetric extends AppCompatActivity { + private static final String TAG = "CheckPerformanceMetric"; + String layout_name = null; + ConstraintLayout mConstraintLayout = null; + ConstraintLayoutStatistics performance = null; + ConstraintLayoutStatistics prePerformance = null; + int loop = 0; + + @Override + protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle extra = getIntent().getExtras(); + String prelayout = extra.getString(Utils.KEY); + layout_name = prelayout; + Context ctx = getApplicationContext(); + int id = ctx.getResources().getIdentifier(prelayout, "layout", ctx.getPackageName()); + setContentView(id); + mConstraintLayout = Utils.findConstraintLayout(this); + performance = new ConstraintLayoutStatistics(mConstraintLayout); + mConstraintLayout.addOnLayoutChangeListener(this::foo); + mConstraintLayout.postDelayed(this::relayout, 1000); + } + + void relayout() { + TextView tv = findViewById(R.id.text); + if (tv != null) { + tv.setText("loop " + (loop++)); + } else { + mConstraintLayout.requestLayout(); + } + mConstraintLayout.postDelayed(this::relayout, 1000); + } + + public void foo(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + log(); + } + + void log() { + Debug.logStack("TAG" ,"CL Perf:", 5); + performance.logSummary("CheckPerformanceMetric", prePerformance); + performance.logSummary("CheckPerformanceMetric"); + prePerformance = performance.clone(); + performance.reset(); + } +} diff --git a/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/VerificationActivity.java b/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/VerificationActivity.java index 9ccf3a465..2d7f1151a 100644 --- a/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/VerificationActivity.java +++ b/projects/MotionLayoutVerification/app/src/main/java/android/support/constraint/app/VerificationActivity.java @@ -81,6 +81,7 @@ public class VerificationActivity extends AppCompatActivity implements View.OnCl private static final boolean DEBUG = false; String layout_name; HashMap> activity_map = new HashMap<>(); + HashMap> activity_class = new HashMap<>(); { activity_map.put("verification_400", CheckSharedValues.class); @@ -100,6 +101,11 @@ public class VerificationActivity extends AppCompatActivity implements View.OnCl activity_map.put("basic_cl_001", CheckDumpJson.class); activity_map.put("basic_cl_002", CheckDumpJson.class); activity_map.put("verification_091", CheckCSTypes.class); + activity_map.put("perf_010", CheckPerformanceMetric.class); + activity_map.put("perf_020", CheckPerformanceMetric.class); + activity_map.put("perf_030", CheckPerformanceMetric.class); + activity_map.put("perf_040", CheckPerformanceMetric.class); + activity_class.put("perf_",CheckPerformanceMetric.class); // activity_map.put("check_cl01", CheckCLPlugin.class); // activity_map.put("verification_037", RotationToolbar.class); // activity_map.put("verification_038", RotationRotateToToolbar.class); @@ -111,8 +117,8 @@ public class VerificationActivity extends AppCompatActivity implements View.OnCl private static boolean REVERSE = false; - private static final String RUN_FIRST = "verification_091";// (true) ? "verification_801" : "bug_005"; - private final String LAYOUTS_MATCHES = "[bcv].*_.*"; + private static final String RUN_FIRST = "perf_030";// (true) ? "verification_801" : "bug_005"; + private final String LAYOUTS_MATCHES = "[bcpv].*_.*"; private static String SHOW_FIRST = ""; MotionLayout mMotionLayout; @@ -688,9 +694,15 @@ public void onFocusChange(View v, boolean hasFocus) { public void launch(String id) { Intent intent; - if (activity_map.containsKey(id)) { - Log.v(TAG, Debug.getLoc() + " launch in activity " + activity_map.get(id).getSimpleName()); - intent = new Intent(this, activity_map.get(id)); + Class to_run = activity_map.get(id); + for (String s1 : activity_class.keySet()) { + if (id.startsWith(s1)) { + to_run = activity_class.get(s1); + } + } + if (to_run != null) { + Log.v(TAG, Debug.getLoc() + " launch in activity " + to_run.getSimpleName()); + intent = new Intent(this, to_run); } else { intent = new Intent(this, VerificationActivity.class); } diff --git a/projects/MotionLayoutVerification/app/src/main/res/drawable/star8.xml b/projects/MotionLayoutVerification/app/src/main/res/drawable/star8.xml index 00012f6e0..59f84f128 100644 --- a/projects/MotionLayoutVerification/app/src/main/res/drawable/star8.xml +++ b/projects/MotionLayoutVerification/app/src/main/res/drawable/star8.xml @@ -7,5 +7,5 @@ - octagram + diff --git a/projects/MotionLayoutVerification/app/src/main/res/layout/perf_001.xml b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_001.xml new file mode 100644 index 000000000..a383be929 --- /dev/null +++ b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_001.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/projects/MotionLayoutVerification/app/src/main/res/layout/perf_002.xml b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_002.xml new file mode 100644 index 000000000..d9042156f --- /dev/null +++ b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_002.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/projects/MotionLayoutVerification/app/src/main/res/layout/perf_003.xml b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_003.xml new file mode 100644 index 000000000..155086944 --- /dev/null +++ b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_003.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/projects/MotionLayoutVerification/app/src/main/res/layout/perf_004.xml b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_004.xml new file mode 100644 index 000000000..8d4720806 --- /dev/null +++ b/projects/MotionLayoutVerification/app/src/main/res/layout/perf_004.xml @@ -0,0 +1,33 @@ + + + + + +