cache

added savetime&timeincache reducing

10/19/2020 5:52:44 AM

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/CSV.java b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/CSV.java
new file mode 100644
index 0000000..1aee4fd
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/CSV.java
@@ -0,0 +1,281 @@
+package br.ufrgs.inf.prosoft.cache.tools;
+
+import br.ufrgs.inf.prosoft.cache.tools.CSV.Row;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+public class CSV implements Iterable<Row> {
+
+    private class Reference {
+
+        String value;
+
+        public Reference() {
+        }
+
+        public Reference(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 7;
+            hash = 11 * hash + Objects.hashCode(this.value);
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this.value == null) {
+                return obj == null;
+            }
+            if (obj instanceof Reference) {
+                return this.value.equals(((Reference) obj).value);
+            }
+            if (obj instanceof String) {
+                return this.value.equals((String) obj);
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return value;
+        }
+    }
+
+    private class Header extends Reference {
+
+        public Header(String value) {
+            super(value);
+        }
+
+    }
+
+    private class Value {
+
+        private final Header header;
+        private Reference reference;
+        private final Row row;
+        private final Column column;
+
+        public Value(Header header, Row row, Column column) {
+            this(header, null, row, column);
+        }
+
+        public Value(Header header, Reference reference, Row row, Column column) {
+            this.header = header;
+            this.reference = reference;
+            this.row = row;
+            this.column = column;
+        }
+
+        public String getProperty() {
+            return header.value;
+        }
+
+        public String getValue() {
+            return reference.value;
+        }
+
+        private void setValue(Reference reference) {
+            this.reference = reference;
+        }
+
+        public Row getRow() {
+            return row;
+        }
+
+        public Column getColumn() {
+            return column;
+        }
+
+        @Override
+        public String toString() {
+            return getProperty() + ": " + getValue();
+        }
+
+    }
+
+    protected class Row implements Iterable<Value> {
+
+        private final List<Value> values;
+
+        public Row(List<Value> values) {
+            if (values == null) {
+                throw new RuntimeException("Tried to create a null row");
+            }
+            this.values = values;
+        }
+
+        public String get(String property) {
+            for (Value value : this) {
+                if (value.getProperty().equals(property)) {
+                    return value.getValue();
+                }
+            }
+            throw new RuntimeException("data does not contain property " + property);
+        }
+
+        @Override
+        public Iterator<Value> iterator() {
+            return this.values.iterator();
+        }
+
+        @Override
+        public String toString() {
+            return values.toString();
+        }
+
+    }
+
+    private class Column extends Row {
+
+        public Column() {
+            this(new ArrayList<>());
+        }
+
+        public Column(List<Value> values) {
+            super(values);
+        }
+    }
+
+    private List<Header> headers;
+    private final List<Row> rows;
+    private final List<Column> columns;
+    private final Map<Header, Map<Reference, Value>> indexes;
+
+    public CSV(String... headers) {
+        this(headers, new String[]{});
+    }
+
+    public CSV(String[] headers, String[] indexes) {
+        this.headers = new ArrayList<>();
+        this.indexes = new HashMap<>();
+        this.columns = new ArrayList<>();
+        this.rows = new ArrayList<>();
+
+        ArrayList<String> indexesList = new ArrayList(Arrays.asList(indexes));
+
+        for (String strHeader : headers) {
+            Header header = new Header(strHeader);
+            this.headers.add(header);
+            if (indexesList.contains(header.toString())) {
+                indexesList.remove(header.toString());
+                this.indexes.put(header, new HashMap<>());
+            }
+            this.columns.add(new Column());
+        }
+        if (!indexesList.isEmpty()) {
+            throw new RuntimeException("indexes not present on headers: " + indexesList);
+        }
+    }
+
+    public CSV append(String... values) {
+        if (values.length != this.headers.size()) {
+            throw new RuntimeException("Values not matching headers length");
+        }
+        List<Value> list = new ArrayList<>();
+        Row row = new Row(list);
+        Iterator<Column> columnsIterator = this.columns.iterator();
+        Iterator<Header> headersIterator = this.headers.iterator();
+        for (String strValue : values) {
+            Header header = headersIterator.next();
+            Reference reference = new Reference(strValue);
+            Value value = new Value(header, reference, row, columnsIterator.next());
+            list.add(value);
+            if (this.indexes.containsKey(header)) {
+                if (this.indexes.get(header).get(reference) != null) {
+                    throw new RuntimeException("duplicate index " + reference + " for " + header);
+                }
+                this.indexes.get(header).put(reference, value);
+            }
+        }
+        this.rows.add(row);
+        return this;
+    }
+
+    private static String[] process(String line) {
+        if (line.contains("'") || line.contains("\"")) {
+            throw new UnsupportedOperationException("Scaped values not supported yet");
+        }
+        return line.split(",");
+    }
+
+    public static CSV read(String path) {
+        return read(path, new String[]{});
+    }
+
+    public static CSV read(String path, String... indexes) {
+        try {
+            List<String> lines = Files.readAllLines(Paths.get(path));
+            if (lines.isEmpty()) {
+                throw new RuntimeException("Empty file");
+            }
+            String headers = lines.remove(0);
+            CSV csv = new CSV(process(headers), indexes);
+            lines.forEach(line -> {
+                csv.append(process(line));
+            });
+            return csv;
+        } catch (IOException ex) {
+            throw new RuntimeException("Cannot read file");
+        }
+    }
+
+    public Optional<Row> selectFirst(String property, String value) {
+        Header mockProperty = new Header(property);
+        Reference mockValue = new Reference(value);
+        if (!this.headers.contains(mockProperty)) {
+            throw new RuntimeException("header not present");
+        }
+        Map<Reference, Value> values = this.indexes.get(mockProperty);
+        if (values != null) {
+            return Optional.ofNullable(values.get(mockValue).getRow());
+        }
+
+        for (Row row : this) {
+            if (row.get(property).equals(value)) {
+                return Optional.ofNullable(row);
+            }
+        }
+        return Optional.empty();
+    }
+
+    public List<Row> select(String property, String value) {
+        Header mockProperty = new Header(property);
+        Reference mockValue = new Reference(value);
+        if (!this.headers.contains(mockProperty)) {
+            throw new RuntimeException("header not present");
+        }
+        List<Row> select = new ArrayList<>();
+
+        Map<Reference, Value> values = this.indexes.get(mockProperty);
+        if (values != null) {
+            select.add(values.get(mockValue).getRow());
+            return select;
+        }
+
+        for (Row row : this) {
+            if (row.get(property).equals(value)) {
+                select.add(row);
+            }
+        }
+        return select;
+    }
+
+    @Override
+    public Iterator<Row> iterator() {
+        return this.rows.iterator();
+    }
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Main.java b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Main.java
index 7516af9..cd2ae9d 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Main.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Main.java
@@ -22,6 +22,7 @@ public class Main {
             System.err.println("--events=<EventsPath> --reduce=<ReducePath> [--prefix=<prefix>]");
             System.err.println("--uncached=<UncachedPath> --reduce=<ReducePath> [--prefix=<prefix> --hash]");
             System.err.println("--events=<EventsPath> --reduce=<ReducePath> --size=true [--prefix=<prefix>]");
+            System.err.println("--events=<EventsPath> --reduce=<ReducePath> --ttls=<TTLsPath> --executions=<ExecutionsPath> [--prefix=<prefix>]");
             System.exit(1);
         }
 
@@ -40,6 +41,8 @@ public class Main {
 
         String eventsPath = arguments.get("events");
         String reducePath = arguments.get("reduce");
+        String ttlsPath = arguments.get("ttls");
+        String executionsPath = arguments.get("executions");
         String prefix = arguments.get("prefix");
         String uncachedPath = arguments.get("uncached");
         String size = arguments.get("size");
@@ -50,7 +53,9 @@ public class Main {
         if (prefix == null) {
             prefix = "";
         }
-        if (eventsPath != null && size != null) {
+        if (ttlsPath != null && executionsPath != null) {
+            Reducer.savedTimeAndTimeInCache(eventsPath, ttlsPath, executionsPath, reducePath, prefix);
+        } else if (eventsPath != null && size != null) {
             Reducer.size(eventsPath, reducePath, prefix);
         } else if (eventsPath != null) {
             Reducer.reduce(eventsPath, reducePath, prefix);
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java
index 549e7da..2ee1713 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java
@@ -14,6 +14,7 @@ import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.function.Consumer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -82,4 +83,85 @@ public class Reducer {
         }
     }
 
+    private static class Method {
+
+        String name;
+        String reference;
+        long ttl;
+        double avgexecution;
+        int hits;
+        int additions;
+
+        double getSavedTime() {
+            return avgexecution * hits;
+        }
+
+        long getTimeInCache() {
+            return ttl * additions;
+        }
+
+    }
+
+    public static void savedTimeAndTimeInCache(String eventsPath, String recommendedTTLsPath, String averageExecutionsPath, String reducePath, String prefix) {
+        CSV recommendedTTLs = CSV.read(recommendedTTLsPath);
+        CSV averageExecutions = CSV.read(averageExecutionsPath);
+
+        Map<String, Method> methods = new HashMap<>();
+
+        recommendedTTLs.forEach(row -> {
+            String reference = row.get("reference");
+            Optional<CSV.Row> selectFirst = averageExecutions.selectFirst("reference", reference);
+            if (selectFirst.isPresent()) {
+                Method method = new Method();
+                method.reference = reference;
+                method.ttl = Long.parseLong(row.get("ttl"));
+                method.avgexecution = Double.parseDouble(selectFirst.get().get("avgexecution"));
+                if (methods.containsKey(reference)) {
+                    throw new RuntimeException("Trying to overwrite reference " + reference);
+                }
+                String uuid = row.get("application") + "," + row.get("version") + "," + row.get("group") + "," + row.get("method");
+                methods.put(uuid, method);
+            }
+        });
+
+        String[] splitPrefix = prefix.split(",");
+        String application = splitPrefix[0];
+        String version = splitPrefix[1];
+        String group = splitPrefix[2];
+
+        String uuid = application + "," + version + "," + group + ",";
+
+        try (Stream<String> lines = Files.lines(Paths.get(eventsPath))) {
+            Gson gson = new Gson();
+            lines.forEach(line -> {
+                CacheEvent event = gson.fromJson(line, CacheEvent.class);
+                if (event.getType().equals(EventType.HIT) || event.getType().equals(EventType.ADDITION)) {
+                    Method method = methods.get(uuid + event.getName());
+                    if (method == null) {
+                        throw new RuntimeException("Method in events was not recommended " + uuid + event.getName());
+                    }
+                    if (event.getType().equals(EventType.HIT)) {
+                        method.hits++;
+                    } else {
+                        method.additions++;
+                    }
+                }
+            });
+
+            try (FileWriter fileWriter = new FileWriter(reducePath, true)) {
+                methods.values().forEach(method -> {
+                    try {
+                        if (method.hits + method.additions > 0) {
+                            fileWriter.write(prefix + method.reference + "," + method.avgexecution + "," + method.ttl + "," + method.additions + "," + method.hits + "," + method.getSavedTime() + "," + method.getTimeInCache() + "\n");
+                        }
+                    } catch (IOException ex) {
+                        LOGGER.log(Level.SEVERE, "IOException {0}", ex);
+                    }
+                });
+            }
+        } catch (IOException ex) {
+            LOGGER.log(Level.SEVERE, "file not found {0}", eventsPath);
+        }
+    }
+
 }