All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.daemon.common.PerfUtils.kt Maven / Gradle / Ivy

/*
 * Copyright 2010-2015 JetBrains s.r.o.
 *
 * 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.
 */

@file:Suppress("NOTHING_TO_INLINE")

package org.jetbrains.kotlin.daemon.common

import java.lang.management.ManagementFactory
import java.lang.management.ThreadMXBean
import java.util.concurrent.atomic.AtomicLong

interface PerfCounters {
    val count: Long
    val time: Long
    val threadTime: Long
    val threadUserTime: Long
    val memory: Long

    fun addMeasurement(time: Long = 0, thread: Long = 0, threadUser: Long = 0, memory: Long = 0)
}

interface Profiler {
    fun getCounters(): Map
    fun getTotalCounters(): PerfCounters

    fun beginMeasure(obj: Any?) : List = listOf()
    fun endMeasure(obj: Any?, startState: List) {}
}

inline fun Profiler.withMeasure(obj: Any?, body: () -> R): R {
    val startState = beginMeasure(obj)
    val res = body()
    endMeasure(obj, startState)
    return res
}


open class SimplePerfCounters : PerfCounters {
    private val _count: AtomicLong = AtomicLong(0L)
    private val _time: AtomicLong = AtomicLong(0L)
    private val _threadTime: AtomicLong = AtomicLong(0L)
    private val _threadUserTime: AtomicLong = AtomicLong(0L)
    private val _memory: AtomicLong = AtomicLong(0L)

    override val count: Long get() = _count.get()
    override val time: Long get() = _time.get()
    override val threadTime: Long get() = _threadTime.get()
    override val threadUserTime: Long get() = _threadUserTime.get()
    override val memory: Long get() = _memory.get()

    override fun addMeasurement(time: Long, thread: Long, threadUser: Long, memory: Long) {
        _count.incrementAndGet()
        _time.addAndGet(time)
        _threadTime.addAndGet(thread)
        _threadUserTime.addAndGet(threadUser)
        _memory.addAndGet(memory)
    }
}


class SimplePerfCountersWithTotal(val totalRef: PerfCounters) : SimplePerfCounters() {
    override fun addMeasurement(time: Long, thread: Long, threadUser: Long, memory: Long) {
        super.addMeasurement(time, thread, threadUser, memory)
        totalRef.addMeasurement(time, thread, threadUser, memory)
    }
}


@Suppress("NOTHING_TO_INLINE")
inline fun ThreadMXBean.threadCpuTime() = if (isCurrentThreadCpuTimeSupported) currentThreadCpuTime else 0L

@Suppress("NOTHING_TO_INLINE")
inline fun ThreadMXBean.threadUserTime() = if (isCurrentThreadCpuTimeSupported) currentThreadUserTime else 0L

@Suppress("NOTHING_TO_INLINE")
inline fun usedMemory(withGC: Boolean): Long {
    if (withGC) {
        System.gc()
    }
    val rt = Runtime.getRuntime()
    return (rt.totalMemory() - rt.freeMemory())
}


inline fun beginMeasureWallTime() = listOf(System.nanoTime())

inline fun endMeasureWallTime(perfCounters: PerfCounters, startState: List) {
    val (startTime) = startState
    perfCounters.addMeasurement(time = System.nanoTime() - startTime) // TODO: add support for time wrapping
}


inline fun beginMeasureWallAndThreadTimes(threadMXBean: ThreadMXBean): List {
    val startTime = System.nanoTime()
    val startThreadTime = threadMXBean.threadCpuTime()
    val startThreadUserTime = threadMXBean.threadUserTime()
    return listOf(startTime, startThreadTime, startThreadUserTime)
}

inline fun endMeasureWallAndThreadTimes(perfCounters: PerfCounters, threadMXBean: ThreadMXBean, startState: List) {
    val (startTime, startThreadTime, startThreadUserTime) = startState

    // TODO: add support for time wrapping
    perfCounters.addMeasurement(time = System.nanoTime() - startTime,
                                thread = threadMXBean.threadCpuTime() - startThreadTime,
                                threadUser = threadMXBean.threadUserTime() - startThreadUserTime)
}

inline fun beginMeasureWallAndThreadTimesAndMemory(withGC: Boolean = false, threadMXBean: ThreadMXBean): List {
    val startMem = usedMemory(withGC)
    val startTime = System.nanoTime()
    val startThreadTime = threadMXBean.threadCpuTime()
    val startThreadUserTime = threadMXBean.threadUserTime()

    return listOf(startMem, startTime, startThreadTime, startThreadUserTime)
}

inline fun endMeasureWallAndThreadTimesAndMemory(perfCounters: PerfCounters, withGC: Boolean = false, threadMXBean: ThreadMXBean, startState: List){
    val (startMem, startTime, startThreadTime, startThreadUserTime) = startState

    // TODO: add support for time wrapping
    perfCounters.addMeasurement(time = System.nanoTime() - startTime,
                                thread = threadMXBean.threadCpuTime() - startThreadTime,
                                threadUser = threadMXBean.threadUserTime() - startThreadUserTime,
                                memory = usedMemory(withGC) - startMem)
}

class DummyProfiler : Profiler {
    override fun getCounters(): Map = mapOf(null to SimplePerfCounters())
    override fun getTotalCounters(): PerfCounters = SimplePerfCounters()
}


abstract class TotalProfiler : Profiler {

    val total = SimplePerfCounters()
    val threadMXBean = ManagementFactory.getThreadMXBean()

    override fun getCounters(): Map = mapOf()
    override fun getTotalCounters(): PerfCounters = total
}


class WallTotalProfiler : TotalProfiler() {
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun beginMeasure(obj: Any?) = beginMeasureWallTime()
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun endMeasure(obj: Any?, startState: List) = endMeasureWallTime(total, startState)
}


class WallAndThreadTotalProfiler : TotalProfiler() {
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun beginMeasure(obj: Any?) = beginMeasureWallAndThreadTimes(threadMXBean)
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun endMeasure(obj: Any?, startState: List) = endMeasureWallAndThreadTimes(total, threadMXBean, startState)
}


class WallAndThreadAndMemoryTotalProfiler(val withGC: Boolean) : TotalProfiler() {
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun beginMeasure(obj: Any?) =
        beginMeasureWallAndThreadTimesAndMemory(withGC, threadMXBean)
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun endMeasure(obj: Any?, startState: List) =
        endMeasureWallAndThreadTimesAndMemory(total, withGC, threadMXBean, startState)
}


class WallAndThreadByClassProfiler() : TotalProfiler() {

    val counters = hashMapOf()

    override fun getCounters(): Map = counters

    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun beginMeasure(obj: Any?) =
        beginMeasureWallAndThreadTimes(threadMXBean)
    @Suppress("OVERRIDE_BY_INLINE")
    override inline fun endMeasure(obj: Any?, startState: List) =
        endMeasureWallAndThreadTimes(counters.getOrPut(obj?.javaClass?.name, { SimplePerfCountersWithTotal(total) }), threadMXBean, startState)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy