• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.caliper.config;
18 
19 import static com.google.caliper.util.Util.subgroupMap;
20 import static com.google.common.base.Preconditions.checkArgument;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.base.Preconditions.checkState;
23 
24 import com.google.caliper.api.ResultProcessor;
25 import com.google.caliper.platform.Platform;
26 import com.google.caliper.platform.VirtualMachineException;
27 import com.google.caliper.util.Util;
28 import com.google.common.annotations.VisibleForTesting;
29 import com.google.common.base.MoreObjects;
30 import com.google.common.base.Strings;
31 import com.google.common.collect.BiMap;
32 import com.google.common.collect.HashBiMap;
33 import com.google.common.collect.ImmutableBiMap;
34 import com.google.common.collect.ImmutableList;
35 import com.google.common.collect.ImmutableMap;
36 import com.google.common.collect.ImmutableSet;
37 
38 import java.io.File;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Map.Entry;
42 import java.util.regex.Matcher;
43 import java.util.regex.Pattern;
44 
45 import javax.annotation.Nullable;
46 
47 /**
48  * Represents caliper configuration.  By default, {@code ~/.caliper/config.properties} and
49  * {@code global-config.properties}.
50  *
51  * @author gak@google.com (Gregory Kick)
52  */
53 public final class CaliperConfig {
54   @VisibleForTesting final ImmutableMap<String, String> properties;
55   private final ImmutableMap<Class<? extends ResultProcessor>, ResultProcessorConfig>
56       resultProcessorConfigs;
57 
58   @VisibleForTesting
CaliperConfig(ImmutableMap<String, String> properties)59   public CaliperConfig(ImmutableMap<String, String> properties)
60       throws InvalidConfigurationException {
61     this.properties = checkNotNull(properties);
62     this.resultProcessorConfigs = findResultProcessorConfigs(subgroupMap(properties, "results"));
63   }
64 
65   private static final Pattern CLASS_PROPERTY_PATTERN = Pattern.compile("(\\w+)\\.class");
66 
mapGroupNamesToClasses( ImmutableMap<String, String> groupProperties, Class<T> type)67   private static <T> ImmutableBiMap<String, Class<? extends T>> mapGroupNamesToClasses(
68       ImmutableMap<String, String> groupProperties, Class<T> type)
69           throws InvalidConfigurationException {
70     BiMap<String, Class<? extends T>> namesToClasses = HashBiMap.create();
71     for (Entry<String, String> entry : groupProperties.entrySet()) {
72       Matcher matcher = CLASS_PROPERTY_PATTERN.matcher(entry.getKey());
73       if (matcher.matches() && !entry.getValue().isEmpty()) {
74         try {
75           Class<?> someClass = Util.loadClass(entry.getValue());
76           checkState(type.isAssignableFrom(someClass));
77           @SuppressWarnings("unchecked")
78           Class<? extends T> verifiedClass = (Class<? extends T>) someClass;
79           namesToClasses.put(matcher.group(1), verifiedClass);
80         } catch (ClassNotFoundException e) {
81           throw new InvalidConfigurationException("Cannot find result processor class: "
82               + entry.getValue());
83         }
84       }
85     }
86     return ImmutableBiMap.copyOf(namesToClasses);
87   }
88 
89   private static ImmutableMap<Class<? extends ResultProcessor>, ResultProcessorConfig>
findResultProcessorConfigs(ImmutableMap<String, String> resultsProperties)90       findResultProcessorConfigs(ImmutableMap<String, String> resultsProperties)
91           throws InvalidConfigurationException {
92     ImmutableBiMap<String, Class<? extends ResultProcessor>> processorToClass =
93         mapGroupNamesToClasses(resultsProperties, ResultProcessor.class);
94     ImmutableMap.Builder<Class<? extends ResultProcessor>, ResultProcessorConfig> builder =
95         ImmutableMap.builder();
96     for (Entry<String, Class<? extends ResultProcessor>> entry : processorToClass.entrySet()) {
97       builder.put(entry.getValue(), getResultProcessorConfig(resultsProperties, entry.getKey()));
98     }
99     return builder.build();
100   }
101 
properties()102   public ImmutableMap<String, String> properties() {
103     return properties;
104   }
105 
106   /**
107    * Returns the configuration of the current host VM (including the flags used to create it). Any
108    * args specified using {@code vm.args} will also be applied
109    */
getDefaultVmConfig(Platform platform)110   public VmConfig getDefaultVmConfig(Platform platform) {
111     return new VmConfig.Builder(platform, platform.defaultVmHomeDir())
112         .addAllOptions(platform.inputArguments())
113         // still incorporate vm.args
114         .addAllOptions(getArgs(subgroupMap(properties, "vm")))
115         .build();
116   }
117 
getVmConfig(Platform platform, String name)118   public VmConfig getVmConfig(Platform platform, String name)
119       throws InvalidConfigurationException {
120     checkNotNull(name);
121     ImmutableMap<String, String> vmGroupMap = subgroupMap(properties, "vm");
122     ImmutableMap<String, String> vmMap = subgroupMap(vmGroupMap, name);
123     File homeDir;
124     try {
125       homeDir = platform.customVmHomeDir(vmGroupMap, name);
126     } catch (VirtualMachineException e) {
127       throw new InvalidConfigurationException(e);
128     }
129     return new VmConfig.Builder(platform, homeDir)
130         .addAllOptions(getArgs(vmGroupMap))
131         .addAllOptions(getArgs(vmMap))
132         .build();
133   }
134 
135   private static final Pattern INSTRUMENT_CLASS_PATTERN = Pattern.compile("([^\\.]+)\\.class");
136 
getConfiguredInstruments()137   public ImmutableSet<String> getConfiguredInstruments() {
138     ImmutableSet.Builder<String> resultBuilder = ImmutableSet.builder();
139     for (String key : subgroupMap(properties, "instrument").keySet()) {
140       Matcher matcher = INSTRUMENT_CLASS_PATTERN.matcher(key);
141       if (matcher.matches()) {
142         resultBuilder.add(matcher.group(1));
143       }
144     }
145     return resultBuilder.build();
146   }
147 
getInstrumentConfig(String name)148   public InstrumentConfig getInstrumentConfig(String name) {
149     checkNotNull(name);
150     ImmutableMap<String, String> instrumentGroupMap = subgroupMap(properties, "instrument");
151     ImmutableMap<String, String> insrumentMap = subgroupMap(instrumentGroupMap, name);
152     @Nullable String className = insrumentMap.get("class");
153     checkArgument(className != null, "no instrument configured named %s", name);
154     return new InstrumentConfig.Builder()
155         .className(className)
156         .addAllOptions(subgroupMap(insrumentMap, "options"))
157         .build();
158   }
159 
getConfiguredResultProcessors()160   public ImmutableSet<Class<? extends ResultProcessor>> getConfiguredResultProcessors() {
161     return resultProcessorConfigs.keySet();
162   }
163 
getResultProcessorConfig( Class<? extends ResultProcessor> resultProcessorClass)164   public ResultProcessorConfig getResultProcessorConfig(
165       Class<? extends ResultProcessor> resultProcessorClass) {
166     return resultProcessorConfigs.get(resultProcessorClass);
167   }
168 
getResultProcessorConfig( ImmutableMap<String, String> resultsProperties, String name)169   private static ResultProcessorConfig getResultProcessorConfig(
170       ImmutableMap<String, String> resultsProperties, String name) {
171     ImmutableMap<String, String> resultsMap = subgroupMap(resultsProperties, name);
172     return new ResultProcessorConfig.Builder()
173         .className(resultsMap.get("class"))
174         .addAllOptions(subgroupMap(resultsMap, "options"))
175         .build();
176   }
177 
toString()178   @Override public String toString() {
179     return MoreObjects.toStringHelper(this)
180         .add("properties", properties)
181         .toString();
182   }
183 
getArgs(Map<String, String> properties)184   private static List<String> getArgs(Map<String, String> properties) {
185     String argsString = Strings.nullToEmpty(properties.get("args"));
186     ImmutableList.Builder<String> args = ImmutableList.builder();
187     StringBuilder arg = new StringBuilder();
188     for (int i = 0; i < argsString.length(); i++) {
189       char c = argsString.charAt(i);
190       switch (c) {
191         case '\\':
192           arg.append(argsString.charAt(++i));
193           break;
194         case ' ':
195           if (arg.length() > 0) {
196             args.add(arg.toString());
197           }
198           arg = new StringBuilder();
199           break;
200         default:
201           arg.append(c);
202           break;
203       }
204     }
205     if (arg.length() > 0) {
206       args.add(arg.toString());
207     }
208     return args.build();
209   }
210 
211 }
212