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
getMemoryStatsnull88 private fun getMemoryStats(): String {
89 val mu = memoryMXBean.getHeapMemoryUsage()
90
91 return String.format(
92 "%dmi %dmu %dmc %dmx",
93 mu.init / 1024 / 1024,
94 mu.used / 1024 / 1024,
95 mu.committed / 1024 / 1024,
96 mu.max / 1024 / 1024)
97 }
98
99 /** Used for verbose output to show progress bar */
100 private var tick = 0
101
102 /** Needed for tests to ensure we don't get unpredictable behavior of "." in output */
resetTickernull103 fun resetTicker() {
104 tick = 0
105 }
106
107 /** Print progress */
ticknull108 fun tick() {
109 tick++
110 if (tick % 100 == 0) {
111 if (!options.verbose) {
112 return
113 }
114 beginningOfLine = false
115 options.stdout.print(".")
116 options.stdout.flush()
117 }
118 }
119