/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.graphics; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import jpcsp.settings.AbstractBoolSettingsListener; import jpcsp.settings.Settings; import org.apache.log4j.Logger; /** * Profiler for the Graphics Engine * * @author gid15 * */ public class GEProfiler { public static Logger log = Logger.getLogger("profiler"); private static boolean profilerEnabled = true; private static ProfilerEnabledSettingsListerner profilerEnabledSettingsListerner; private static final Long zero = new Long(0); private static HashMap<Integer, Long> cmdCounts = new HashMap<Integer, Long>(); private static HashMap<Integer, Long> primVtypeCounts = new HashMap<Integer, Long>(); private static HashMap<Integer, String> vtypeNames = new HashMap<Integer, String>(); private static long geListCount; private static long textureLoadCount; private static long copyGeToMemoryCount; private static long copyStencilToMemoryCount; private static long geListDurationMicros; private static class ProfilerEnabledSettingsListerner extends AbstractBoolSettingsListener { @Override protected void settingsValueChanged(boolean value) { setProfilerEnabled(value); } } public static void initialise() { if (profilerEnabledSettingsListerner == null) { profilerEnabledSettingsListerner = new ProfilerEnabledSettingsListerner(); Settings.getInstance().registerSettingsListener("Profiler", "emu.profiler", profilerEnabledSettingsListerner); } reset(); } private static void setProfilerEnabled(boolean enabled) { profilerEnabled = enabled; } public static boolean isProfilerEnabled() { return profilerEnabled; } public static void reset() { if (!profilerEnabled) { return; } cmdCounts.clear(); primVtypeCounts.clear(); vtypeNames.clear(); geListCount = 0; textureLoadCount = 0; copyGeToMemoryCount = 0; geListDurationMicros = 0; } public static void exit() { if (!profilerEnabled) { return; } log.info("------------------ GEProfiler ----------------------"); log.info(String.format("GE list count: %d", geListCount)); log.info(String.format("Texture load count: %d, average %.1f per GE list", textureLoadCount, textureLoadCount / (double) geListCount)); log.info(String.format("Copy GE to memory: %d, average %.1f per GE list", copyGeToMemoryCount, copyGeToMemoryCount / (double) geListCount)); log.info(String.format("Copy Stencil to memory: %d, average %.1f per GE list", copyStencilToMemoryCount, copyStencilToMemoryCount / (double) geListCount)); log.info(String.format("GE list duration: %dms, average %.1fms per GE list, max FPS is %.1f", geListDurationMicros / 1000, geListDurationMicros / (double) geListCount / 1000, 1000000 / (geListDurationMicros / (double) geListCount))); GeCommands geCommands = GeCommands.getInstance(); for (Integer cmd : cmdCounts.keySet()) { Long cmdCount = cmdCounts.get(cmd); log.info(String.format("%s: called %d times, average %.1f per GE list", geCommands.getCommandString(cmd.intValue()), cmdCount.longValue(), cmdCount.longValue() / (double) geListCount)); } // Sort the primVtypeCounts based on their counts (highest count first). List<Integer> primVtypeSorted = new ArrayList<Integer>(primVtypeCounts.keySet()); Collections.sort(primVtypeSorted, new Comparator<Integer>() { @Override public int compare(Integer vtype1, Integer vtype2) { return -primVtypeCounts.get(vtype1).compareTo(primVtypeCounts.get(vtype2)); } }); for (Integer vtype : primVtypeSorted) { Long vtypeCount = primVtypeCounts.get(vtype); log.info(String.format("%s: used %d times in PRIM, average %.1f per GE list", vtypeNames.get(vtype), vtypeCount.longValue(), vtypeCount.longValue() / (double) geListCount)); } } public static void startGeList() { geListCount++; } public static void startGeCmd(int cmd) { Long cmdCount = cmdCounts.get(cmd); if (cmdCount == null) { cmdCount = zero; } cmdCounts.put(cmd, cmdCount + 1); if (cmd == GeCommands.PRIM) { VertexInfo vinfo = VideoEngine.getInstance().getContext().vinfo; int vtype = vinfo.vtype; Long vtypeCount = primVtypeCounts.get(vtype); if (vtypeCount == null) { vtypeCount = zero; vtypeNames.put(vtype, vinfo.toString()); } primVtypeCounts.put(vtype, vtypeCount + 1); } } public static void loadTexture() { textureLoadCount++; } public static void copyGeToMemory() { copyGeToMemoryCount++; } public static void copyStencilToMemory() { copyStencilToMemoryCount++; } public static void geListDuration(long micros) { geListDurationMicros += micros; } }