mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Log PNG/SVG icons load time statistics
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
package com.intellij.internal;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.util.FieldAccessor;
|
||||
import com.intellij.util.ImageLoader;
|
||||
import com.intellij.util.ImageLoader.LoadFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Logs load time statistics for PNG/SVG images, such as: average, median, ide startup total, first N icons total.
|
||||
*
|
||||
* @author tav
|
||||
*/
|
||||
public class IconsLoadTime extends DumbAwareAction {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.internal.IconsLoadTime");
|
||||
|
||||
private static final boolean IS_INTERNAL_MODE = Boolean.valueOf(System.getProperty("idea.is.internal")).booleanValue();
|
||||
private static final int STATS_LIMIT = 10000;
|
||||
private static final int FIXED_SCOPE = 100; // log stats for a first fixed number of icons
|
||||
|
||||
private static final List<Integer> stats = IS_INTERNAL_MODE ? Collections.synchronizedList(new LinkedList<>()) : null; // load time per icon
|
||||
|
||||
static {
|
||||
if (IS_INTERNAL_MODE) new FieldAccessor<>(ImageLoader.class, "measureLoad").set(null, (LoadFunction)func -> measure(Objects.requireNonNull(func)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
log(false);
|
||||
}
|
||||
|
||||
private static void log(boolean measureStartupLoad) {
|
||||
if (stats == null || stats.isEmpty()) return;
|
||||
|
||||
int size = stats.size();
|
||||
long sum = stats.stream().mapToInt(Integer::intValue).sum();
|
||||
long average = sum / size;
|
||||
long median = (size % 2 == 0) ? stats.get(size / 2 - 1) + stats.get(size / 2) : stats.get(size / 2);
|
||||
|
||||
Function<Long, String> ms = (nano) -> String.format("%.02fms", nano / 1000000f);
|
||||
|
||||
LOG.info((Registry.is("ide.svg.icon") ? "SVG" : "PNG") +
|
||||
" load time: " +
|
||||
(measureStartupLoad ? "ide_startup=" : "total=") + ms.apply(sum) +
|
||||
", average=" + ms.apply(average) +
|
||||
", median=" + ms.apply(median) +
|
||||
"; number of icons: " + size);
|
||||
}
|
||||
|
||||
private static Image measure(LoadFunction func) throws IOException {
|
||||
boolean measure = stats.size() < STATS_LIMIT;
|
||||
long t = measure ? System.nanoTime() : 0;
|
||||
|
||||
Image img = func.load(null);
|
||||
|
||||
if (measure) {
|
||||
stats.add((int)(System.nanoTime() - t));
|
||||
if (stats.size() == FIXED_SCOPE) log(false);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
public static class StartupLoadTime implements StartupActivity, DumbAware {
|
||||
@Override
|
||||
public void runActivity(@NotNull Project project) {
|
||||
if (IS_INTERNAL_MODE) log(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,6 +286,8 @@
|
||||
|
||||
<welcomeFrameProvider implementation="com.intellij.openapi.wm.impl.welcomeScreen.FlatWelcomeFrameProvider"/>
|
||||
|
||||
<postStartupActivity implementation="com.intellij.internal.IconsLoadTime$StartupLoadTime"/>
|
||||
|
||||
<!-- General -->
|
||||
<applicationConfigurable groupId="appearance" groupWeight="120" key="title.general" bundle="messages.IdeBundle" id="preferences.general"
|
||||
instance="com.intellij.ide.GeneralSettingsConfigurable"/>
|
||||
|
||||
@@ -260,6 +260,8 @@
|
||||
<action id="CloseEditor" class="com.intellij.ide.actions.CloseEditorAction"/>
|
||||
<action id="PinActiveTab" class="com.intellij.ide.actions.PinActiveTabAction"/>
|
||||
|
||||
<action id="IconsLoadTime" internal="true" class="com.intellij.internal.IconsLoadTime" text="Log icons load time"/>
|
||||
|
||||
<group id="MainMenu">
|
||||
<group id="FileMenu" popup="true">
|
||||
<group id="FileOpenGroup">
|
||||
|
||||
@@ -55,7 +55,7 @@ public class FieldAccessor<E, T> {
|
||||
}
|
||||
|
||||
public T get(@Nullable E object) {
|
||||
if (!isAvailable() || object == null) return null;
|
||||
if (!isAvailable()) return null;
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
T value = (T)myFieldRef.get().get(object);
|
||||
@@ -68,7 +68,7 @@ public class FieldAccessor<E, T> {
|
||||
}
|
||||
|
||||
public void set(@Nullable E object, @Nullable T value) {
|
||||
if (!isAvailable() || object == null) return;
|
||||
if (!isAvailable()) return;
|
||||
try {
|
||||
myFieldRef.get().set(object, value);
|
||||
}
|
||||
|
||||
@@ -54,21 +54,51 @@ public class ImageLoader implements Serializable {
|
||||
public static final int CACHED_IMAGE_MAX_SIZE = (int)Math.round(Registry.doubleValue("ide.cached.image.max.size") * 1024 * 1024);
|
||||
private static final ConcurrentMap<String, Image> ourCache = ContainerUtil.createConcurrentSoftValueMap();
|
||||
|
||||
private static final boolean SVG_ENABLED = Registry.is("ide.svg.icon");
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"}) // set from com.intellij.internal.IconsLoadTime
|
||||
private static LoadFunction measureLoad;
|
||||
|
||||
/**
|
||||
* For internal usage.
|
||||
*/
|
||||
public interface LoadFunction {
|
||||
Image load(@Nullable LoadFunction delegate) throws IOException;
|
||||
}
|
||||
|
||||
private static class ImageDesc {
|
||||
public enum Type {
|
||||
PNG,
|
||||
|
||||
SVG {
|
||||
@Override
|
||||
public Image load(URL url, InputStream is, double scale) throws IOException {
|
||||
return SVGLoader.load(url, is, scale);
|
||||
public Image load(final URL url, final InputStream is, final double scale) throws IOException {
|
||||
LoadFunction f = new LoadFunction() {
|
||||
@Override
|
||||
public Image load(LoadFunction delegate) throws IOException {
|
||||
return SVGLoader.load(url, is, scale);
|
||||
}
|
||||
};
|
||||
if (measureLoad != null && SVG_ENABLED) {
|
||||
return measureLoad.load(f);
|
||||
}
|
||||
return f.load(null);
|
||||
}
|
||||
},
|
||||
|
||||
UNDEFINED;
|
||||
|
||||
public Image load(URL url, InputStream stream, double scale) throws IOException {
|
||||
return ImageLoader.load(stream, scale);
|
||||
public Image load(final URL url, final InputStream is, final double scale) throws IOException {
|
||||
LoadFunction f = new LoadFunction() {
|
||||
@Override
|
||||
public Image load(LoadFunction delegate) {
|
||||
return ImageLoader.load(is, scale);
|
||||
}
|
||||
};
|
||||
if (measureLoad != null && !SVG_ENABLED) {
|
||||
return measureLoad.load(f);
|
||||
}
|
||||
return f.load(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,23 +200,21 @@ public class ImageLoader implements Serializable {
|
||||
{
|
||||
ImageDescList vars = new ImageDescList();
|
||||
|
||||
boolean ideSvgIconSupport = Registry.is("ide.svg.icon");
|
||||
|
||||
// Prefer retina images for HiDPI scale, because downscaling
|
||||
// retina images provides a better result than upscaling non-retina images.
|
||||
boolean retina = JBUI.isHiDPI(ctx.getScale(PIX_SCALE));
|
||||
|
||||
if (retina || dark || ideSvgIconSupport) {
|
||||
if (retina || dark || SVG_ENABLED) {
|
||||
final String name = FileUtil.getNameWithoutExtension(file);
|
||||
final String ext = FileUtilRt.getExtension(file);
|
||||
|
||||
double scale = adjustScaleFactor(allowFloatScaling, ctx.getScale(PIX_SCALE));
|
||||
|
||||
if (ideSvgIconSupport && dark) {
|
||||
if (SVG_ENABLED && dark) {
|
||||
vars.add(new ImageDesc(name + "_dark.svg", cls, scale, ImageDesc.Type.SVG));
|
||||
}
|
||||
|
||||
if (ideSvgIconSupport) {
|
||||
if (SVG_ENABLED) {
|
||||
vars.add(new ImageDesc(name + ".svg", cls, scale, ImageDesc.Type.SVG));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user