diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceCache.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceCache.java index 188e8eee832ca72329da2314e8bc43105d5035b0..99a42718049cd6b434a2aaa3caeb6fa2b3a9d657 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceCache.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceCache.java @@ -4,6 +4,12 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Singleton flyweight factory that creates and caches human faces. Faces are @@ -27,7 +33,7 @@ public abstract class HumanFaceCache { /** * Keep at least this portion of the Java heap memory free */ - public static double MIN_FREE_MEMORY = 0.05; // 5% + public static final double MIN_FREE_MEMORY = 0.05; // 5% private final Map<String, HumanFace> inMemoryFaces = new HashMap<>(); private final Map<String, File> dumpedFaces = new HashMap<>(); @@ -48,6 +54,7 @@ public abstract class HumanFaceCache { public HumanFace loadFace(File file) { try { String faceId = file.getCanonicalPath(); + //String faceId = Long.toHexString(Double.doubleToLongBits(Math.random())); // In memory face: HumanFace face = inMemoryFaces.get(faceId); @@ -63,7 +70,8 @@ public abstract class HumanFaceCache { // New face: return storeNewFace(file); - } catch (IOException|ClassNotFoundException ex) { + } catch (IOException|ClassNotFoundException|InterruptedException|ExecutionException ex) { + Logger.getLogger(HumanFaceCache.class.getName()).log(Level.SEVERE, null, ex); return null; } } @@ -90,7 +98,8 @@ public abstract class HumanFaceCache { // New face: return null; - } catch (IOException|ClassNotFoundException ex) { + } catch (IOException|ClassNotFoundException|InterruptedException|ExecutionException ex) { + Logger.getLogger(HumanFaceCache.class.getName()).log(Level.SEVERE, null, ex); return null; } } @@ -120,38 +129,53 @@ public abstract class HumanFaceCache { } /** - * Recovers the face from the dump file. Heap memory is released (some existing + * Recovers the face from the dump file.Heap memory is released (some existing * face is dumped) if necessary. * * @param faceId Face ID * @return Recovered face or {@code null} if the face was not dumped. * @throws IOException on I/O error * @throws ClassNotFoundException on I/O error + * @throws java.lang.InterruptedException + * @throws java.util.concurrent.ExecutionException */ - protected HumanFace recoverFace(String faceId) throws IOException, ClassNotFoundException { + protected HumanFace recoverFace(String faceId) throws IOException, ClassNotFoundException, InterruptedException, ExecutionException { File dumpFile = dumpedFaces.get(faceId); if (dumpFile == null) { return null; } - freeMemory(); - HumanFace face = HumanFace.restoreFromFile(dumpFile); + + // Free memory and recover human face from dump file silultanously: + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + final Future<HumanFace> result = executor.submit(() -> HumanFace.restoreFromFile(dumpFile)); + executor.submit(() -> freeMemory()); + executor.shutdown(); + while (!executor.isTerminated()){} + HumanFace face = result.get(); + inMemoryFaces.put(faceId, face); dumpedFaces.remove(faceId); return face; } /** - * Instantiates new face. Heap memory is released (some existing face is dumped) if necessary. + * Instantiates new face.Heap memory is released (some existing face is dumped) if necessary. * * @param file OBJ file * @return Face instance. * @throws IOException on I/O error + * @throws java.lang.InterruptedException + * @throws java.util.concurrent.ExecutionException */ - protected HumanFace storeNewFace(File file) throws IOException { - HumanFace face = new HumanFace(file); - freeMemory(); + protected HumanFace storeNewFace(File file) throws IOException, InterruptedException, ExecutionException { + // Free memory and load human face simultaneously: + ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + final Future<HumanFace> result = executor.submit(() -> new HumanFace(file)); + executor.submit(() -> freeMemory()); + executor.shutdown(); + while (!executor.isTerminated()){} + HumanFace face = result.get(); inMemoryFaces.put(face.getId(), face); - //inMemoryFaces.put(Long.toHexString(Double.doubleToLongBits(Math.random())), face); return face; } @@ -167,9 +191,12 @@ public abstract class HumanFaceCache { return false; } String faceId = selectFaceForDump(); - HumanFace face = inMemoryFaces.remove(faceId); - dumpedFaces.put(faceId, face.dumpToFile()); - return true; + if (faceId != null) { + HumanFace face = inMemoryFaces.remove(faceId); + dumpedFaces.put(faceId, face.dumpToFile()); + return true; + } + return false; } /** @@ -180,7 +207,9 @@ public abstract class HumanFaceCache { protected abstract String selectFaceForDump(); protected static String formatSize(long v) { - if (v < 1024) return v + " B"; + if (v < 1024) { + return v + " B"; + } int z = (63 - Long.numberOfLeadingZeros(v)) / 10; return String.format("%.1f %sB", (double)v / (1L << (z*10)), " KMGTPE".charAt(z)); } diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFacePrivilegedCache.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFacePrivilegedCache.java index 38df62054d92ed0ac7d5c50b555d1c53e722238e..3c73e046761d1ce4022f86bba360ac01ce3b8a5a 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFacePrivilegedCache.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFacePrivilegedCache.java @@ -1,6 +1,7 @@ package cz.fidentis.analyst.face; import java.io.IOException; +import java.util.concurrent.ExecutionException; /** * This cache preserves the first X faces (privileged faces) always in the memory. @@ -58,7 +59,7 @@ public class HumanFacePrivilegedCache extends HumanFaceCache { } @Override - protected HumanFace recoverFace(String faceId) throws IOException, ClassNotFoundException { + protected HumanFace recoverFace(String faceId) throws IOException, ClassNotFoundException, InterruptedException, ExecutionException { HumanFace face = super.recoverFace(faceId); if (face != null) { this.recoveredFace = face.getId(); diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java b/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java index 410e864d48d9dd0f64886cf8624838bcaa49a586..1d373075e860d79e97ac53d920ad0899e4d26fcd 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java +++ b/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java @@ -45,7 +45,7 @@ public class EfficiencyTests { face1.getMeshModel().simplifyModel(); face2.getMeshModel().simplifyModel(); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 10; i++) { HumanFace face = HumanFacePrivilegedCache.instance().loadFace(faceFile4); face.getMeshModel().simplifyModel(); System.out.println(i+".\t" + HumanFacePrivilegedCache.instance());