aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/actions/LocalHostResourceManagerLinux.java
blob: 59ab78775aa8f6f441c1707aa7d2fb1a79731003 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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 com.google.devtools.build.lib.actions;

import com.google.common.base.Splitter;
import com.google.common.io.Files;
import com.google.devtools.build.lib.unix.ProcMeminfoParser;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;

/**
 * This class estimates the local host's resource capacity for Linux.
 */
public class LocalHostResourceManagerLinux {
  private static String cpuInfoContent = null;

  private static final Splitter NEWLINE_SPLITTER = Splitter.on('\n').omitEmptyStrings();
  private static final String CPU_INFO_FILE = "/proc/cpuinfo";
  private static final String MEM_INFO_FILE = "/proc/meminfo";

  private static int getLogicalCpuCount() throws IOException {
    String content = getCpuInfoContent();
    return getLogicalCpuCountHelper(content);
  }

  private static int getPhysicalCpuCount(int logicalCpuCount) throws IOException {
    String content = getCpuInfoContent();
    return getPhysicalCpuCountHelper(logicalCpuCount, content);
  }

  private static double getMemoryInMb() throws IOException {
    return getMemoryInMbHelper(MEM_INFO_FILE);
  }

  public static ResourceSet getLocalHostResources() {
    try {
      int logicalCpuCount = getLogicalCpuCount();
      int physicalCpuCount = getPhysicalCpuCount(logicalCpuCount);
      double ramMb = getMemoryInMb();

      boolean hyperthreading = (logicalCpuCount != physicalCpuCount);
      final double EFFECTIVE_CPUS_PER_HYPERTHREADED_CPU = 0.6;
      return ResourceSet.create(
          ramMb,
          logicalCpuCount * (hyperthreading ? EFFECTIVE_CPUS_PER_HYPERTHREADED_CPU : 1.0),
          1.0,
          Integer.MAX_VALUE);
    } catch (IOException | IllegalArgumentException e) {
      return null;
    }
  }

  private static String getCpuInfoContent() throws IOException {
    if (cpuInfoContent == null) {
      cpuInfoContent = readContent(CPU_INFO_FILE);
    }
    return cpuInfoContent;
  }

  private static String readContent(String filename) throws IOException {
    return Files.toString(new File(filename), Charset.defaultCharset());
  }

  /**
   * For testing purposes only. Do not use it.
   */
  public static int getLogicalCpuCountHelper(String content) throws IOException {
    int count = 0;
    Iterable<String> lines = NEWLINE_SPLITTER.split(content);
    for (String line : lines) {
      if (line.startsWith("processor")) {
        count++;
      }
    }
    if (count == 0) {
      throw new IllegalArgumentException("Can't get logical CPU count");
    }
    return count;
  }

  public static int getPhysicalCpuCountHelper(int logicalCpuCount, String content)
      throws IOException {
    // CPU count
    Iterable<String> lines = NEWLINE_SPLITTER.split(content);
    Set<String> uniq = new HashSet<>();
    for (String line : lines) {
      if (line.startsWith("physical id")) {
        uniq.add(line);
      }
    }
    int cpuCount = uniq.size();
    if (cpuCount == 0) {
      cpuCount = logicalCpuCount;
    }

    // core per CPU
    uniq = new HashSet<>();
    for (String line : lines) {
      if (line.startsWith("core id")) {
        uniq.add(line);
      }
    }
    int coresPerCpu = uniq.size();
    if (coresPerCpu == 0) {
      coresPerCpu = 1;
    }

    return cpuCount * coresPerCpu;
  }

  public static double getMemoryInMbHelper(String memInfoFileName) throws IOException {
    ProcMeminfoParser memInfo = new ProcMeminfoParser(memInfoFileName);
    double ramMb = ProcMeminfoParser.kbToMb(memInfo.getTotalKb());
    return ramMb;
  }
}