src/java.base/linux/classes/jdk/internal/platform/cgroupv1/Metrics.java
changeset 50545 292a4a87c321
child 54040 56adab1e0edd
equal deleted inserted replaced
50544:5f20bf95c052 50545:292a4a87c321
       
     1 /*
       
     2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  *
       
    23  * or visit www.oracle.com if you need additional information or have any
       
    24  * questions.
       
    25  */
       
    26 
       
    27 package jdk.internal.platform.cgroupv1;
       
    28 
       
    29 import java.io.BufferedReader;
       
    30 import java.io.IOException;
       
    31 import java.nio.file.Files;
       
    32 import java.nio.file.Path;
       
    33 import java.nio.file.Paths;
       
    34 import java.util.stream.Stream;
       
    35 
       
    36 public class Metrics implements jdk.internal.platform.Metrics {
       
    37     private SubSystem memory;
       
    38     private SubSystem cpu;
       
    39     private SubSystem cpuacct;
       
    40     private SubSystem cpuset;
       
    41     private SubSystem blkio;
       
    42     private boolean activeSubSystems;
       
    43 
       
    44     // Values returned larger than this number are unlimited.
       
    45     static long unlimited_minimum = 0x7FFFFFFFFF000000L;
       
    46 
       
    47     private static final Metrics INSTANCE = initContainerSubSystems();
       
    48 
       
    49     private static final String PROVIDER_NAME = "cgroupv1";
       
    50 
       
    51     private Metrics() {
       
    52         activeSubSystems = false;
       
    53     }
       
    54 
       
    55     public static Metrics getInstance() {
       
    56         return INSTANCE;
       
    57     }
       
    58 
       
    59     private static Metrics initContainerSubSystems() {
       
    60         Metrics metrics = new Metrics();
       
    61 
       
    62         /**
       
    63          * Find the cgroup mount points for subsystems
       
    64          * by reading /proc/self/mountinfo
       
    65          *
       
    66          * Example for docker MemorySubSystem subsystem:
       
    67          * 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/MemorySubSystem ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,MemorySubSystem
       
    68          *
       
    69          * Example for host:
       
    70          * 34 28 0:29 / /sys/fs/cgroup/MemorySubSystem rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,MemorySubSystem
       
    71          */
       
    72         try (Stream<String> lines =
       
    73              Files.lines(Paths.get("/proc/self/mountinfo"))) {
       
    74 
       
    75             lines.filter(line -> line.contains(" - cgroup "))
       
    76                  .map(line -> line.split(" "))
       
    77                  .forEach(entry -> createSubSystem(metrics, entry));
       
    78 
       
    79         } catch (IOException e) {
       
    80             return null;
       
    81         }
       
    82 
       
    83         /**
       
    84          * Read /proc/self/cgroup and map host mount point to
       
    85          * local one via /proc/self/mountinfo content above
       
    86          *
       
    87          * Docker example:
       
    88          * 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb044
       
    89          *
       
    90          * Host example:
       
    91          * 5:memory:/user.slice
       
    92          *
       
    93          * Construct a path to the process specific memory and cpuset
       
    94          * cgroup directory.
       
    95          *
       
    96          * For a container running under Docker from memory example above
       
    97          * the paths would be:
       
    98          *
       
    99          * /sys/fs/cgroup/memory
       
   100          *
       
   101          * For a Host from memory example above the path would be:
       
   102          *
       
   103          * /sys/fs/cgroup/memory/user.slice
       
   104          *
       
   105          */
       
   106         try (Stream<String> lines =
       
   107              Files.lines(Paths.get("/proc/self/cgroup"))) {
       
   108 
       
   109             lines.map(line -> line.split(":"))
       
   110                  .filter(line -> (line.length >= 3))
       
   111                  .forEach(line -> setSubSystemPath(metrics, line));
       
   112 
       
   113         } catch (IOException e) {
       
   114             return null;
       
   115         }
       
   116 
       
   117         // Return Metrics object if we found any subsystems.
       
   118         if (metrics.activeSubSystems()) {
       
   119             return metrics;
       
   120         }
       
   121 
       
   122         return null;
       
   123     }
       
   124 
       
   125     /**
       
   126      * createSubSystem objects and initialize mount points
       
   127      */
       
   128     private static void createSubSystem(Metrics metric, String [] mountentry) {
       
   129         if (mountentry.length < 5) return;
       
   130 
       
   131         Path p = Paths.get(mountentry[4]);
       
   132         String subsystemName = p.getFileName().toString();
       
   133 
       
   134         if (subsystemName != null) {
       
   135             switch (subsystemName) {
       
   136                 case "memory":
       
   137                     metric.setMemorySubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   138                     break;
       
   139                 case "cpuset":
       
   140                     metric.setCpuSetSubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   141                     break;
       
   142                 case "cpu,cpuacct":
       
   143                 case "cpuacct,cpu":
       
   144                     metric.setCpuSubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   145                     metric.setCpuAcctSubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   146                     break;
       
   147                 case "cpuacct":
       
   148                     metric.setCpuAcctSubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   149                     break;
       
   150                 case "cpu":
       
   151                     metric.setCpuSubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   152                     break;
       
   153                 case "blkio":
       
   154                     metric.setBlkIOSubSystem(new SubSystem(mountentry[3], mountentry[4]));
       
   155                     break;
       
   156                 default:
       
   157                     // Ignore subsystems that we don't support
       
   158                     break;
       
   159             }
       
   160         }
       
   161     }
       
   162 
       
   163     /**
       
   164      * setSubSystemPath based on the contents of /proc/self/cgroup
       
   165      */
       
   166     private static void setSubSystemPath(Metrics metric, String [] entry) {
       
   167         String controller;
       
   168         String base;
       
   169         SubSystem subsystem = null;
       
   170         SubSystem subsystem2 = null;
       
   171 
       
   172         controller = entry[1];
       
   173         base = entry[2];
       
   174         if (controller != null && base != null) {
       
   175             switch (controller) {
       
   176                 case "memory":
       
   177                     subsystem = metric.MemorySubSystem();
       
   178                     break;
       
   179                 case "cpuset":
       
   180                     subsystem = metric.CpuSetSubSystem();
       
   181                     break;
       
   182                 case "cpu,cpuacct":
       
   183                 case "cpuacct,cpu":
       
   184                     subsystem = metric.CpuSubSystem();
       
   185                     subsystem2 = metric.CpuAcctSubSystem();
       
   186                     break;
       
   187                 case "cpuacct":
       
   188                     subsystem = metric.CpuAcctSubSystem();
       
   189                     break;
       
   190                 case "cpu":
       
   191                     subsystem = metric.CpuSubSystem();
       
   192                     break;
       
   193                 case "blkio":
       
   194                     subsystem = metric.BlkIOSubSystem();
       
   195                     break;
       
   196                 // Ignore subsystems that we don't support
       
   197                 default:
       
   198                     break;
       
   199             }
       
   200         }
       
   201 
       
   202         if (subsystem != null) {
       
   203             subsystem.setPath(base);
       
   204             metric.setActiveSubSystems();
       
   205         }
       
   206         if (subsystem2 != null) {
       
   207             subsystem2.setPath(base);
       
   208         }
       
   209     }
       
   210 
       
   211 
       
   212     private void setActiveSubSystems() {
       
   213         activeSubSystems = true;
       
   214     }
       
   215 
       
   216     private boolean activeSubSystems() {
       
   217         return activeSubSystems;
       
   218     }
       
   219 
       
   220     private void setMemorySubSystem(SubSystem memory) {
       
   221         this.memory = memory;
       
   222     }
       
   223 
       
   224     private void setCpuSubSystem(SubSystem cpu) {
       
   225         this.cpu = cpu;
       
   226     }
       
   227 
       
   228     private void setCpuAcctSubSystem(SubSystem cpuacct) {
       
   229         this.cpuacct = cpuacct;
       
   230     }
       
   231 
       
   232     private void setCpuSetSubSystem(SubSystem cpuset) {
       
   233         this.cpuset = cpuset;
       
   234     }
       
   235 
       
   236     private void setBlkIOSubSystem(SubSystem blkio) {
       
   237         this.blkio = blkio;
       
   238     }
       
   239 
       
   240     private SubSystem MemorySubSystem() {
       
   241         return memory;
       
   242     }
       
   243 
       
   244     private SubSystem CpuSubSystem() {
       
   245         return cpu;
       
   246     }
       
   247 
       
   248     private SubSystem CpuAcctSubSystem() {
       
   249         return cpuacct;
       
   250     }
       
   251 
       
   252     private SubSystem CpuSetSubSystem() {
       
   253         return cpuset;
       
   254     }
       
   255 
       
   256     private SubSystem BlkIOSubSystem() {
       
   257         return blkio;
       
   258     }
       
   259 
       
   260     public String getProvider() {
       
   261         return PROVIDER_NAME;
       
   262     }
       
   263 
       
   264     /*****************************************************************
       
   265      * CPU Accounting Subsystem
       
   266      ****************************************************************/
       
   267 
       
   268 
       
   269     public long getCpuUsage() {
       
   270         return SubSystem.getLongValue(cpuacct, "cpuacct.usage");
       
   271     }
       
   272 
       
   273     public long[] getPerCpuUsage() {
       
   274         String usagelist = SubSystem.getStringValue(cpuacct, "cpuacct.usage_percpu");
       
   275         if (usagelist == null) {
       
   276             return new long[0];
       
   277         }
       
   278 
       
   279         String list[] = usagelist.split(" ");
       
   280         long percpu[] = new long[list.length];
       
   281         for (int i = 0; i < list.length; i++) {
       
   282             percpu[i] = Long.parseLong(list[i]);
       
   283         }
       
   284         return percpu;
       
   285     }
       
   286 
       
   287     public long getCpuUserUsage() {
       
   288         return SubSystem.getLongEntry(cpuacct, "cpuacct.stat", "user");
       
   289     }
       
   290 
       
   291     public long getCpuSystemUsage() {
       
   292         return SubSystem.getLongEntry(cpuacct, "cpuacct.stat", "system");
       
   293     }
       
   294 
       
   295 
       
   296     /*****************************************************************
       
   297      * CPU Subsystem
       
   298      ****************************************************************/
       
   299 
       
   300 
       
   301     public long getCpuPeriod() {
       
   302         return SubSystem.getLongValue(cpuacct, "cpu.cfs_period_us");
       
   303     }
       
   304 
       
   305     public long getCpuQuota() {
       
   306         return SubSystem.getLongValue(cpuacct, "cpu.cfs_quota_us");
       
   307     }
       
   308 
       
   309     public long getCpuShares() {
       
   310         long retval = SubSystem.getLongValue(cpuacct, "cpu.shares");
       
   311         if (retval == 0 || retval == 1024)
       
   312             return -1;
       
   313         else
       
   314             return retval;
       
   315     }
       
   316 
       
   317     public long getCpuNumPeriods() {
       
   318         return SubSystem.getLongEntry(cpuacct, "cpu.stat", "nr_periods");
       
   319     }
       
   320 
       
   321     public long getCpuNumThrottled() {
       
   322         return SubSystem.getLongEntry(cpuacct, "cpu.stat", "nr_throttled");
       
   323     }
       
   324 
       
   325     public long getCpuThrottledTime() {
       
   326         return SubSystem.getLongEntry(cpuacct, "cpu.stat", "throttled_time");
       
   327     }
       
   328 
       
   329     public long getEffectiveCpuCount() {
       
   330         return Runtime.getRuntime().availableProcessors();
       
   331     }
       
   332 
       
   333 
       
   334     /*****************************************************************
       
   335      * CPUSet Subsystem
       
   336      ****************************************************************/
       
   337 
       
   338     public int[] getCpuSetCpus() {
       
   339         return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.cpus"));
       
   340     }
       
   341 
       
   342     public int[] getEffectiveCpuSetCpus() {
       
   343         return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.effective_cpus"));
       
   344     }
       
   345 
       
   346     public int[] getCpuSetMems() {
       
   347         return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.mems"));
       
   348     }
       
   349 
       
   350     public int[] getEffectiveCpuSetMems() {
       
   351         return SubSystem.StringRangeToIntArray(SubSystem.getStringValue(cpuset, "cpuset.effective_mems"));
       
   352     }
       
   353 
       
   354     public double getCpuSetMemoryPressure() {
       
   355         return SubSystem.getDoubleValue(cpuset, "cpuset.memory_pressure");
       
   356     }
       
   357 
       
   358     public boolean isCpuSetMemoryPressureEnabled() {
       
   359         long val = SubSystem.getLongValue(cpuset, "cpuset.memory_pressure_enabled");
       
   360         return (val == 1);
       
   361     }
       
   362 
       
   363 
       
   364     /*****************************************************************
       
   365      * Memory Subsystem
       
   366      ****************************************************************/
       
   367 
       
   368 
       
   369     public long getMemoryFailCount() {
       
   370         return SubSystem.getLongValue(memory, "memory.failcnt");
       
   371     }
       
   372 
       
   373     public long getMemoryLimit() {
       
   374         long retval = SubSystem.getLongValue(memory, "memory.limit_in_bytes");
       
   375         return retval > unlimited_minimum ? -1L : retval;
       
   376     }
       
   377 
       
   378     public long getMemoryMaxUsage() {
       
   379         return SubSystem.getLongValue(memory, "memory.max_usage_in_bytes");
       
   380     }
       
   381 
       
   382     public long getMemoryUsage() {
       
   383         return SubSystem.getLongValue(memory, "memory.usage_in_bytes");
       
   384     }
       
   385 
       
   386     public long getKernelMemoryFailCount() {
       
   387         return SubSystem.getLongValue(memory, "memory.kmem.failcnt");
       
   388     }
       
   389 
       
   390     public long getKernelMemoryLimit() {
       
   391         long retval = SubSystem.getLongValue(memory, "memory.kmem.limit_in_bytes");
       
   392         return retval > unlimited_minimum ? -1L : retval;
       
   393     }
       
   394 
       
   395     public long getKernelMemoryMaxUsage() {
       
   396         return SubSystem.getLongValue(memory, "memory.kmem.max_usage_in_bytes");
       
   397     }
       
   398 
       
   399     public long getKernelMemoryUsage() {
       
   400         return SubSystem.getLongValue(memory, "memory.kmem.usage_in_bytes");
       
   401     }
       
   402 
       
   403     public long getTcpMemoryFailCount() {
       
   404         return SubSystem.getLongValue(memory, "memory.kmem.tcp.failcnt");
       
   405     }
       
   406 
       
   407     public long getTcpMemoryLimit() {
       
   408         long retval =  SubSystem.getLongValue(memory, "memory.kmem.tcp.limit_in_bytes");
       
   409         return retval > unlimited_minimum ? -1L : retval;
       
   410     }
       
   411 
       
   412     public long getTcpMemoryMaxUsage() {
       
   413         return SubSystem.getLongValue(memory, "memory.kmem.tcp.max_usage_in_bytes");
       
   414     }
       
   415 
       
   416     public long getTcpMemoryUsage() {
       
   417         return SubSystem.getLongValue(memory, "memory.kmem.tcp.usage_in_bytes");
       
   418     }
       
   419 
       
   420     public long getMemoryAndSwapFailCount() {
       
   421         return SubSystem.getLongValue(memory, "memory.memsw.failcnt");
       
   422     }
       
   423 
       
   424     public long getMemoryAndSwapLimit() {
       
   425         long retval = SubSystem.getLongValue(memory, "memory.memsw.limit_in_bytes");
       
   426         return retval > unlimited_minimum ? -1L : retval;
       
   427     }
       
   428 
       
   429     public long getMemoryAndSwapMaxUsage() {
       
   430         return SubSystem.getLongValue(memory, "memory.memsw.max_usage_in_bytes");
       
   431     }
       
   432 
       
   433     public long getMemoryAndSwapUsage() {
       
   434         return SubSystem.getLongValue(memory, "memory.memsw.usage_in_bytes");
       
   435     }
       
   436 
       
   437     public boolean isMemoryOOMKillEnabled() {
       
   438         long val = SubSystem.getLongEntry(memory, "memory.oom_control", "oom_kill_disable");
       
   439         return (val == 0);
       
   440     }
       
   441 
       
   442     public long getMemorySoftLimit() {
       
   443         long retval = SubSystem.getLongValue(memory, "memory.soft_limit_in_bytes");
       
   444         return retval > unlimited_minimum ? -1L : retval;
       
   445     }
       
   446 
       
   447 
       
   448     /*****************************************************************
       
   449      * BlKIO Subsystem
       
   450      ****************************************************************/
       
   451 
       
   452 
       
   453     public long getBlkIOServiceCount() {
       
   454         return SubSystem.getLongEntry(blkio, "blkio.throttle.io_service_bytes", "Total");
       
   455     }
       
   456 
       
   457     public long getBlkIOServiced() {
       
   458         return SubSystem.getLongEntry(blkio, "blkio.throttle.io_serviced", "Total");
       
   459     }
       
   460 
       
   461 }