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

org.jetbrains.kotlin.utils.Profiler 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.utils;

import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NotNull;

import java.io.PrintStream;
import java.util.Arrays;
import java.util.Stack;
import java.util.concurrent.locks.ReentrantLock;

public class Profiler {
    // The stack is synchronized here: this is intentional
    private static final ThreadLocal> PROFILERS = new ThreadLocal>() {
        @Override
        protected Stack initialValue() {
            return new Stack<>();
        }
    };

    private static final ReentrantLock OUT_LOCK = new ReentrantLock();

    @NotNull
    public static Profiler create(@NotNull String name) {
        //noinspection UseOfSystemOutOrSystemErr
        return create(name, System.out);
    }

    @NotNull
    public static Profiler create(@NotNull String name, @NotNull PrintStream out) {
        return create(name, new PrintingLogger(out));
    }

    @NotNull
    public static Profiler create(@NotNull String name, @NotNull Logger log) {
        Profiler profiler = new Profiler(name, log);
        PROFILERS.get().push(profiler);
        return profiler;
    }

    public static Profiler getFromContext() {
        Stack profilers = PROFILERS.get();
        if (profilers.isEmpty()) {
            throw new UnsupportedOperationException();
        }
        return profilers.peek();
    }

    private final String name;
    private final Logger log;
    private long start = Long.MAX_VALUE;
    private long cumulative = 0;
    private boolean paused = true;
    private StackTraceElement[] stackTrace;
    private boolean mute;
    private String formatString;

    private Profiler(@NotNull String name, @NotNull Logger log) {
        this.name = name;
        this.log = log;
        setPrintAccuracy(3);
    }

    public Profiler recordStackTrace(int depth) {
        return recordStackTrace(1 /*skipping this frame*/, depth);
    }

    public Profiler recordStackTrace(int skip, int depth) {
        StackTraceElement[] trace = new Throwable().getStackTrace();

        int from = 1 + skip;
        if (from >= trace.length) return this;

        int to;
        if (depth == -1) {
            to = trace.length;
        }
        else {
            to = Math.min(skip + depth + 1, trace.length);
        }

        stackTrace = Arrays.copyOfRange(trace, from, to);
        return this;
    }

    public Profiler resetStackTrace() {
        stackTrace = null;
        return this;
    }

    public Profiler printStackTrace() {
        if (stackTrace != null && log.isDebugEnabled()) {
            OUT_LOCK.lock();
            try {
                for (StackTraceElement element : stackTrace) {
                    println("\tat ", element);
                }
            }
            finally {
                OUT_LOCK.unlock();
            }
        }
        return this;
    }

    public Profiler printEntering() {
        println("Entering ", name);
        return this;
    }

    public Profiler printThreadName() {
        println(Thread.currentThread().getName() + " ", name);
        return this;
    }

    public Profiler start() {
        if (paused) {
            start = System.nanoTime();
            paused = false;
        }
        return this;
    }

    public Profiler end() {
        long result = cumulative;
        if (!paused) {
            result += System.nanoTime() - start;
        }
        paused = true;
        cumulative = 0;

        if (!mute && log.isDebugEnabled()) {
            OUT_LOCK.lock();
            try {
                println(name, " took ", format(result));
                printStackTrace();
            }
            finally {
                OUT_LOCK.unlock();
            }
        }

        return this;
    }

    public Profiler pause() {
        if (!paused) {
            cumulative += System.nanoTime() - start;
            paused = true;
        }
        return this;
    }

    public long getCumulative() {
        return cumulative;
    }

    public Profiler mute() {
        mute = true;
        return this;
    }

    public Profiler unmute() {
        mute = false;
        return this;
    }

    public Profiler println(Object message) {
        if (!mute && log.isDebugEnabled()) {
            log.debug(String.valueOf(message));
        }
        return this;
    }

    public Profiler println(Object a, Object b) {
        if (!mute && log.isDebugEnabled()) {
            OUT_LOCK.lock();
            try {
                log.debug(String.valueOf(a) + b);
            }
            finally {
                OUT_LOCK.unlock();
            }
        }
        return this;
    }

    public Profiler println(Object a, Object b, Object c) {
        if (!mute && log.isDebugEnabled()) {
            OUT_LOCK.lock();
            try {
                log.debug(String.valueOf(a) + b + c);
            }
            finally {
                OUT_LOCK.unlock();
            }
        }
        return this;
    }

    public Profiler println(Object a, Object b, Object c, Object... rest) {
        if (!mute && log.isDebugEnabled()) {
            OUT_LOCK.lock();
            try {
                StringBuilder sb = new StringBuilder();
                sb.append(a);
                sb.append(b);
                sb.append(c);
                for (Object o : rest) {
                    sb.append(o);
                }
                log.debug(sb.toString());
            }
            finally {
                OUT_LOCK.unlock();
            }
        }
        return this;
    }

    public Profiler setPrintAccuracy(int accuracy) {
        formatString = "%." + accuracy + "fs";
        return this;
    }

    private String format(long delta) {
        return String.format(formatString, delta / 1e9);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy