1/*
2 * Copyright (C) 2010 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
17package com.google.caliper.runner;
18
19import com.google.caliper.model.Host;
20import com.google.common.collect.ImmutableMultimap;
21import com.google.common.collect.ImmutableMultiset;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Multimap;
24import com.google.common.io.Files;
25
26import java.io.File;
27import java.io.IOException;
28import java.nio.charset.Charset;
29import java.util.Collection;
30import java.util.List;
31import java.util.Map;
32import java.util.TreeMap;
33
34/**
35 * An instance of this class is responsible for returning a Map that describes the environment:
36 * JVM version, os details, etc.
37 */
38final class EnvironmentGetter {
39  Host getHost() {
40    return new Host.Builder()
41        .addAllProperies(getProperties())
42        .build();
43  }
44
45  private Map<String, String> getProperties() {
46    TreeMap<String, String> propertyMap = Maps.newTreeMap();
47
48    Map<String, String> sysProps = Maps.fromProperties(System.getProperties());
49
50    // Sometimes java.runtime.version is more descriptive than java.version
51    String version = sysProps.get("java.version");
52    String alternateVersion = sysProps.get("java.runtime.version");
53    if (alternateVersion != null && alternateVersion.length() > version.length()) {
54      version = alternateVersion;
55    }
56    propertyMap.put("host.availableProcessors",
57        Integer.toString(Runtime.getRuntime().availableProcessors()));
58
59    String osName = sysProps.get("os.name");
60    propertyMap.put("os.name", osName);
61    propertyMap.put("os.version", sysProps.get("os.version"));
62    propertyMap.put("os.arch", sysProps.get("os.arch"));
63
64    if (osName.equals("Linux")) {
65      getLinuxEnvironment(propertyMap);
66    }
67
68    return propertyMap;
69  }
70
71  private void getLinuxEnvironment(Map<String, String> propertyMap) {
72    // the following probably doesn't work on ALL linux
73    Multimap<String, String> cpuInfo = propertiesFromLinuxFile("/proc/cpuinfo");
74    propertyMap.put("host.cpus", Integer.toString(cpuInfo.get("processor").size()));
75    String s = "cpu cores";
76    propertyMap.put("host.cpu.cores", describe(cpuInfo, s));
77    propertyMap.put("host.cpu.names", describe(cpuInfo, "model name"));
78    propertyMap.put("host.cpu.cachesize", describe(cpuInfo, "cache size"));
79
80    Multimap<String, String> memInfo = propertiesFromLinuxFile("/proc/meminfo");
81    // TODO redo memInfo.toString() so we don't get square brackets
82    propertyMap.put("host.memory.physical", memInfo.get("MemTotal").toString());
83    propertyMap.put("host.memory.swap", memInfo.get("SwapTotal").toString());
84  }
85
86  private static String describe(Multimap<String, String> cpuInfo, String s) {
87    Collection<String> strings = cpuInfo.get(s);
88    // TODO redo the ImmutableMultiset.toString() call so we don't get square brackets
89    return (strings.size() == 1)
90        ? strings.iterator().next()
91        : ImmutableMultiset.copyOf(strings).toString();
92  }
93
94  /**
95   * Returns the key/value pairs from the specified properties-file like file.
96   * Unlike standard Java properties files, {@code reader} is allowed to list
97   * the same property multiple times. Comments etc. are unsupported.
98   *
99   * <p>If there's any problem reading the file's contents, we'll return an
100   * empty Multimap.
101   */
102  private static Multimap<String, String> propertiesFromLinuxFile(String file) {
103    try {
104      List<String> lines = Files.readLines(new File(file), Charset.defaultCharset());
105      ImmutableMultimap.Builder<String, String> result = ImmutableMultimap.builder();
106      for (String line : lines) {
107        // TODO(schmoe): replace with Splitter (in Guava release 10)
108        String[] parts = line.split("\\s*\\:\\s*", 2);
109        if (parts.length == 2) {
110          result.put(parts[0], parts[1]);
111        }
112      }
113      return result.build();
114    } catch (IOException e) {
115      // If there's any problem reading the file, just return an empty multimap.
116      return ImmutableMultimap.of();
117    }
118  }
119}
120