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

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

There is a newer version: 2.0.0
Show newest version
/*
 * 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.
 */

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 withMeasure(obj: Any?, body: () -> R): R
}


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 withMeasureWallTime(perfCounters: PerfCounters, body: () -> R): R {
    val startTime = System.nanoTime()
    val res = body()
    perfCounters.addMeasurement(time = System.nanoTime() - startTime) // TODO: add support for time wrapping
    return res
}


inline fun withMeasureWallAndThreadTimes(perfCounters: PerfCounters, threadMXBean: ThreadMXBean, body: () -> R): R {
    val startTime = System.nanoTime()
    val startThreadTime = threadMXBean.threadCpuTime()
    val startThreadUserTime = threadMXBean.threadUserTime()

    val res = body()

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

inline fun withMeasureWallAndThreadTimes(perfCounters: PerfCounters, body: () -> R): R = withMeasureWallAndThreadTimes(perfCounters, ManagementFactory.getThreadMXBean(), body)


inline fun withMeasureWallAndThreadTimesAndMemory(perfCounters: PerfCounters, withGC: Boolean = false, threadMXBean: ThreadMXBean, body: () -> R): R {
    val startMem = usedMemory(withGC)
    val startTime = System.nanoTime()
    val startThreadTime = threadMXBean.threadCpuTime()
    val startThreadUserTime = threadMXBean.threadUserTime()

    val res = body()

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

inline fun withMeasureWallAndThreadTimesAndMemory(perfCounters: PerfCounters, withGC: Boolean, body: () -> R): R =
        withMeasureWallAndThreadTimesAndMemory(perfCounters, withGC, ManagementFactory.getThreadMXBean(), body)


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

    override final inline fun  withMeasure(obj: Any?, body: () -> R): R = body()
}


abstract class TotalProfiler : Profiler {

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

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


class WallTotalProfiler : TotalProfiler() {
    override final inline fun  withMeasure(obj: Any?, body: () -> R): R = withMeasureWallTime(total, body)
}


class WallAndThreadTotalProfiler : TotalProfiler() {
    override final inline fun  withMeasure(obj: Any?, body: () -> R): R = withMeasureWallAndThreadTimes(total, threadMXBean, body)
}


class WallAndThreadAndMemoryTotalProfiler(val withGC: Boolean) : TotalProfiler() {
    override final inline fun  withMeasure(obj: Any?, body: () -> R): R = withMeasureWallAndThreadTimesAndMemory(total, withGC, threadMXBean, body)
}


class WallAndThreadByClassProfiler() : TotalProfiler() {

    val counters = hashMapOf()

    override fun getCounters(): Map = counters

    override final inline fun  withMeasure(obj: Any?, body: () -> R): R =
            withMeasureWallAndThreadTimes(counters.getOrPut(obj?.javaClass?.name, { SimplePerfCountersWithTotal(total) }), threadMXBean, body)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy