• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
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 package com.android.tools.metalava
17 
18 import java.time.LocalDateTime
19 import java.time.format.DateTimeFormatter
20 
21 private val PROGRESS_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
22 private var beginningOfLine = true
23 private var firstProgress = true
24 
25 /** Print a progress message with a timestamp when --verbose is enabled. */
progressnull26 fun progress(message: String) {
27     if (!options.verbose) {
28         return
29     }
30     if (!beginningOfLine) {
31         options.stdout.println()
32     }
33     val now = LocalDateTime.now().format(PROGRESS_TIME_FORMATTER)
34 
35     if (!firstProgress) {
36         options.stdout.print(now)
37         options.stdout.print("   CPU: ")
38         options.stdout.println(getCpuStats())
39 
40         options.stdout.print(now)
41         options.stdout.print("   MEM: ")
42         options.stdout.println(getMemoryStats())
43     }
44     firstProgress = false
45 
46     options.stdout.print(now)
47     options.stdout.print(" ")
48     options.stdout.print(message)
49     options.stdout.flush()
50     beginningOfLine = message.endsWith('\n')
51 }
52 
53 private var lastMillis: Long = -1L
54 private var lastUserMillis: Long = -1L
55 private var lastCpuMillis: Long = -1L
56 
getCpuStatsnull57 private fun getCpuStats(): String {
58     val nowMillis = System.currentTimeMillis()
59     val userMillis = threadMXBean.getCurrentThreadUserTime() / 1000_000
60     val cpuMillis = threadMXBean.getCurrentThreadCpuTime() / 1000_000
61 
62     if (lastMillis == -1L) {
63         lastMillis = nowMillis
64     }
65     if (lastUserMillis == -1L) {
66         lastUserMillis = userMillis
67     }
68     if (lastCpuMillis == -1L) {
69         lastCpuMillis = cpuMillis
70     }
71 
72     val realDeltaMs = nowMillis - lastMillis
73     val userDeltaMillis = userMillis - lastUserMillis
74     // Sometimes we'd get "-0.0" without the max.
75     val sysDeltaMillis = Math.max(0, cpuMillis - lastCpuMillis - userDeltaMillis)
76 
77     lastMillis = nowMillis
78     lastUserMillis = userMillis
79     lastCpuMillis = cpuMillis
80 
81     return String.format(
82         "+%.1freal +%.1fusr +%.1fsys",
83         realDeltaMs / 1_000.0,
84         userDeltaMillis / 1_000.0,
85         sysDeltaMillis / 1_000.0
86     )
87 }
88 
getMemoryStatsnull89 private fun getMemoryStats(): String {
90     val mu = memoryMXBean.getHeapMemoryUsage()
91 
92     return String.format(
93         "%dmi %dmu %dmc %dmx",
94         mu.init / 1024 / 1024,
95         mu.used / 1024 / 1024,
96         mu.committed / 1024 / 1024,
97         mu.max / 1024 / 1024
98     )
99 }
100 
101 /** Used for verbose output to show progress bar */
102 private var tick = 0
103 
104 /** Needed for tests to ensure we don't get unpredictable behavior of "." in output */
resetTickernull105 fun resetTicker() {
106     tick = 0
107 }
108 
109 /** Print progress */
ticknull110 fun tick() {
111     tick++
112     if (tick % 100 == 0) {
113         if (!options.verbose) {
114             return
115         }
116         beginningOfLine = false
117         options.stdout.print(".")
118         options.stdout.flush()
119     }
120 }
121