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 17 package com.android.tools.metalava 18 19 import java.io.PrintWriter 20 import java.time.LocalDateTime 21 import java.time.format.DateTimeFormatter 22 import kotlin.math.max 23 24 class ProgressTracker( 25 private val verbose: Boolean = false, 26 private val stdout: PrintWriter = PrintWriter(System.out), 27 ) { 28 private val progressTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS") 29 private var beginningOfLine = true 30 private var firstProgress = true 31 32 /** Print a progress message with a timestamp when --verbose is enabled. */ progressnull33 fun progress(message: String) { 34 if (!verbose) { 35 return 36 } 37 if (!beginningOfLine) { 38 stdout.println() 39 } 40 val now = LocalDateTime.now().format(progressTimeFormatter) 41 42 if (!firstProgress) { 43 stdout.print(now) 44 stdout.print(" CPU: ") 45 stdout.println(getCpuStats()) 46 47 stdout.print(now) 48 stdout.print(" MEM: ") 49 stdout.println(getMemoryStats()) 50 } 51 firstProgress = false 52 53 stdout.print(now) 54 stdout.print(" ") 55 stdout.print(message) 56 stdout.flush() 57 beginningOfLine = message.endsWith('\n') 58 } 59 60 private var lastMillis: Long = -1L 61 private var lastUserMillis: Long = -1L 62 private var lastCpuMillis: Long = -1L 63 getCpuStatsnull64 private fun getCpuStats(): String { 65 val nowMillis = System.currentTimeMillis() 66 val userMillis = threadMXBean.currentThreadUserTime / 1000_000 67 val cpuMillis = threadMXBean.currentThreadCpuTime / 1000_000 68 69 if (lastMillis == -1L) { 70 lastMillis = nowMillis 71 } 72 if (lastUserMillis == -1L) { 73 lastUserMillis = userMillis 74 } 75 if (lastCpuMillis == -1L) { 76 lastCpuMillis = cpuMillis 77 } 78 79 val realDeltaMs = nowMillis - lastMillis 80 val userDeltaMillis = userMillis - lastUserMillis 81 // Sometimes we'd get "-0.0" without the max. 82 val sysDeltaMillis = max(0, cpuMillis - lastCpuMillis - userDeltaMillis) 83 84 lastMillis = nowMillis 85 lastUserMillis = userMillis 86 lastCpuMillis = cpuMillis 87 88 return String.format( 89 "+%.1freal +%.1fusr +%.1fsys", 90 realDeltaMs / 1_000.0, 91 userDeltaMillis / 1_000.0, 92 sysDeltaMillis / 1_000.0 93 ) 94 } 95 getMemoryStatsnull96 private fun getMemoryStats(): String { 97 val mu = memoryMXBean.heapMemoryUsage 98 99 return String.format( 100 "%dmi %dmu %dmc %dmx", 101 mu.init / 1024 / 1024, 102 mu.used / 1024 / 1024, 103 mu.committed / 1024 / 1024, 104 mu.max / 1024 / 1024 105 ) 106 } 107 } 108