/* * This file is part of JOP, the Java Optimized Processor * see <http://www.jopdesign.com/> * * Copyright (C) 2011, Stefan Hepp (stefan@stefant.org). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.jcopter.greedy; import com.jopdesign.common.AppInfo; import com.jopdesign.common.MethodInfo; import com.jopdesign.common.code.CallGraph.DUMPTYPE; import com.jopdesign.common.config.BooleanOption; import com.jopdesign.common.config.Config; import com.jopdesign.common.config.Config.BadConfigurationException; import com.jopdesign.common.config.EnumOption; import com.jopdesign.common.config.IntegerOption; import com.jopdesign.common.config.OptionGroup; import com.jopdesign.common.config.StringOption; import com.jopdesign.jcopter.JCopter; import com.jopdesign.jcopter.JCopterConfig; import com.jopdesign.jcopter.analysis.MethodCacheAnalysis.AnalysisType; import com.jopdesign.wcet.ipet.IPETConfig.CacheCostCalculationMethod; import org.apache.log4j.Logger; import java.io.File; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * @author Stefan Hepp (stefan@stefant.org) */ public class GreedyConfig { public enum GreedyOrder { Global, Targets, WCAFirst, TopDown, BottomUp } private static final EnumOption<GreedyOrder> GREEDY_ORDER = new EnumOption<GreedyOrder>("order", "sets the order in which the optimizer selects regions in the callgraph to optimize", GreedyOrder.WCAFirst); // TODO maybe move this to JCopterConfig as global option? Could be used for other optimizations if we ever have them private static final StringOption TARGETS = new StringOption("targets", "comma separated list of target methods for callgraph based optimizations or 'wca' for wca-targets or 'all' for whole app", "main"); private static final BooleanOption USE_WCEP = new BooleanOption("use-wcep", "Optimize only methods on the WCET path if WCA is enabled", true); private static final BooleanOption USE_WCA_EXEC_COUNT = new BooleanOption("use-wcep-ef", "Use execution frequencies from the WCA if the WCA is enabled", false); private static final BooleanOption USE_FREQUENCY_ONLY = new BooleanOption("use-freq-only", "Assume an execution count of 1 for every method", false); private static final EnumOption<AnalysisType> CACHE_ANALYSIS_TYPE = new EnumOption<AnalysisType>("cache-analysis", "Select the cache analysis type", AnalysisType.ALWAYS_HIT); private static final EnumOption<CacheCostCalculationMethod> WCA_CACHE_APPROXIMATION = new EnumOption<CacheCostCalculationMethod>("wca-cache-analysis", "Set the cache analysis type to be used by the WCA", CacheCostCalculationMethod.ALL_FIT_REGIONS); private static final EnumOption<DUMPTYPE> DUMP_TARGET_CALLGRAPH = new EnumOption<DUMPTYPE>("dump-target-callgraph", "Dump the callgraph of the target methods", DUMPTYPE.off); // This is for debugging, to find bad optimizations in log n iterations private static final IntegerOption MAX_STEPS = new IntegerOption("max-steps", "Optimize at most n candidates", true); private static final StringOption DUMP_STATS = new StringOption("dump-stats", "Filename of a CSV file to dump optimization stats into", true); private static final Logger logger = Logger.getLogger(JCopter.LOG_OPTIMIZER+".GreedyConfig"); private final AppInfo appInfo; private final JCopter jcopter; private final OptionGroup options; private List<MethodInfo> targets; private boolean useWCEP; public static void registerOptions(OptionGroup options) { options.addOption(GREEDY_ORDER); options.addOption(TARGETS); options.addOption(USE_WCEP); options.addOption(USE_WCA_EXEC_COUNT); options.addOption(USE_FREQUENCY_ONLY); options.addOption(CACHE_ANALYSIS_TYPE); options.addOption(WCA_CACHE_APPROXIMATION); options.addOption(DUMP_TARGET_CALLGRAPH); options.addOption(MAX_STEPS); options.addOption(DUMP_STATS); } public GreedyConfig(JCopter jcopter, OptionGroup greedyOptions) throws BadConfigurationException { this.jcopter = jcopter; this.options = greedyOptions; appInfo = AppInfo.getSingleton(); loadOptions(); } private void loadOptions() throws BadConfigurationException { String targetNames = options.getOption(TARGETS); if ("all".equals(targetNames)) { targets = new ArrayList<MethodInfo>( AppInfo.getSingleton().getCallGraph().getRootMethods() ); } else if ("wca".equals(targetNames)) { targets = jcopter.getJConfig().getWCATargets(); } else { targets = Config.parseMethodList(targetNames); } useWCEP = useWCA() && options.getOption(USE_WCEP); GreedyOrder order = getOrder(); if (useWCEP && (order == GreedyOrder.BottomUp || order == GreedyOrder.TopDown)) { if (options.isSet(USE_WCEP)) { logger.warn("WCEP selector does not work with order "+order+", falling back to local WCET selector"); } useWCEP = false; } } public AppInfo getAppInfo() { return appInfo; } public JCopter getJCopter() { return jcopter; } public JCopterConfig getJConfig() { return jcopter.getJConfig(); } public GreedyOrder getOrder() { return options.getOption(GREEDY_ORDER); } public List<MethodInfo> getTargetMethods() { return targets; } public Set<MethodInfo> getTargetMethodSet() { return new LinkedHashSet<MethodInfo>(targets); } public AnalysisType getCacheAnalysisType() { return options.getOption(CACHE_ANALYSIS_TYPE); } public boolean useMethodCacheStrategy() { return !options.hasValue(WCA_CACHE_APPROXIMATION); } public CacheCostCalculationMethod getCacheApproximation() { CacheCostCalculationMethod defaultValue = options.getOption(WCA_CACHE_APPROXIMATION); if (defaultValue != null) { return defaultValue; } AnalysisType analysisType = getCacheAnalysisType(); if (analysisType == AnalysisType.ALWAYS_HIT) { return CacheCostCalculationMethod.ALWAYS_HIT; } if (analysisType == AnalysisType.ALWAYS_MISS) { return CacheCostCalculationMethod.ALWAYS_MISS; } if (analysisType == AnalysisType.ALWAYS_MISS_OR_HIT) { return CacheCostCalculationMethod.ALL_FIT_SIMPLE; } return CacheCostCalculationMethod.ALL_FIT_REGIONS; } public List<MethodInfo> getWCATargets() { // we could override this for this optimization return jcopter.getJConfig().getWCATargets(); } public Set<MethodInfo> getWCATargetSet() { return new LinkedHashSet<MethodInfo>(getWCATargets()); } public boolean useWCA() { return jcopter.useWCA(); } public boolean useWCEP() { return useWCEP; } public boolean useWCAExecCount() { return options.getOption(USE_WCA_EXEC_COUNT); } public boolean useLocalExecCount() { return options.getOption(USE_FREQUENCY_ONLY); } public int getMaxCodesize() { // TODO make this configurable, set default maxCodesize in constructor return jcopter.getJConfig().getMaxCodesize(); } public DUMPTYPE getTargetCallgraphDumpType() { return options.getOption(DUMP_TARGET_CALLGRAPH); } public int getMaxSteps() { return (options.getOption(MAX_STEPS, 0L)).intValue(); } public boolean doDumpStats() { return options.isSet(DUMP_STATS); } public File getStatsFile() { return (doDumpStats()) ? new File(options.getOption(DUMP_STATS)) : null; } }