Method.java

125 lines | 5.367 kB Blame History Raw Download
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufrgs.inf.prosoft.aplcachetf.extension.metadata;

import br.ufrgs.inf.prosoft.aplcachetf.extension.metrics.CacheabilityPatternDecider;
import br.ufrgs.inf.prosoft.tfcache.Metrics;
import br.ufrgs.inf.prosoft.tfcache.Pareto;
import br.ufrgs.inf.prosoft.tfcache.StorageManager;
import br.ufrgs.inf.prosoft.tfcache.configuration.Configuration;
import br.ufrgs.inf.prosoft.tfcache.metadata.Occurrence;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author root
 */
public class Method {

    private static final Logger LOGGER = Logger.getLogger(Method.class.getName());

    private final String name;
    private final List<Occurrence> occurrences;
    private List<GroupOfOccurrences> groupsOfOccurrences;
    private Metrics bestTFMetrics;

    public Method(String name, List<Occurrence> occurrences) {
        this.name = name;
        if (occurrences == null) throw new RuntimeException("Occurrences is null");
        if (occurrences.isEmpty()) throw new RuntimeException("Occurrences is empty");
        this.occurrences = occurrences;
    }

    public String getName() {
        return this.name;
    }

    public Metrics getBestTFMetrics() {
        return this.bestTFMetrics;
    }

    public double getEstimatedSavedTime() {
        if (getBestTFMetrics() != null) return getBestTFMetrics().getSavedTime();
        return groupsOfOccurrences().map(it -> it.getMetrics().getSavedTime()).reduce(Double::sum).orElse(0D);
    }

    public Stream<Occurrence> occurrences() {
        return this.occurrences.stream();
    }

    public Stream<GroupOfOccurrences> groupsOfOccurrences() {
        if (this.groupsOfOccurrences == null) groupByInput();
        return this.groupsOfOccurrences.stream();
    }

    private void groupByInput() {
        Map<String, List<Occurrence>> inputHasOccurrences = new ConcurrentHashMap<>();
        occurrences().forEach(occurrence -> {
            String parameters = occurrence.getParametersSerialised();
            inputHasOccurrences.compute(parameters, (key, oldValue) -> {
                if (oldValue == null) oldValue = new ArrayList<>();
                oldValue.add(occurrence);
                return oldValue;
            });
        });
        this.groupsOfOccurrences = inputHasOccurrences.entrySet().stream()
                .map(entry -> new GroupOfOccurrences(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    public void removeSingleOccurrences() {
        if (this.groupsOfOccurrences == null) groupByInput();
        int initialCountOfOccurrences = this.groupsOfOccurrences.size();
        this.groupsOfOccurrences.removeIf(groupOfOccurrences -> groupOfOccurrences.occurrences().count() < 2);
        int removedOccurrences = initialCountOfOccurrences - this.groupsOfOccurrences.size();
        if (removedOccurrences > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} inputs from method {2}", removedOccurrences, initialCountOfOccurrences, this.name));
    }

    public void removeNotRecommendedInputs() {
        if (this.groupsOfOccurrences == null) throw new RuntimeException("Recommendations not called");
        int initialCountOfOccurrences = this.groupsOfOccurrences.size();
        this.groupsOfOccurrences.removeIf(it -> it.getMetrics().getPareto().getBestMetrics().getSavedTime() == 0);
        int removedOccurrences = initialCountOfOccurrences - this.groupsOfOccurrences.size();
        if (removedOccurrences > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} inputs from method {2}", removedOccurrences, initialCountOfOccurrences, this.name));
    }

    public void calculateMetrics() {
        if (this.groupsOfOccurrences == null) groupByInput();
        groupsOfOccurrences().forEach(GroupOfOccurrences::calculateMetrics);
        String uuid = Configuration.getUUID().replace("level:input", "level:method");
        Pareto pareto = StorageManager.get(uuid, this.occurrences);
        if (pareto != null) this.bestTFMetrics = pareto.getBestMetrics();
    }

    public void calculateThresholds() {
        this.groupsOfOccurrences.forEach(GroupOfOccurrences::calculateThresholds);
    }

    public void filterCacheableInputs() {
        int initialInputsSize = this.groupsOfOccurrences.size();
        this.groupsOfOccurrences.removeIf(CacheabilityPatternDecider::isNotCacheable);
        int removedInputs = initialInputsSize - this.groupsOfOccurrences.size();
        if (removedInputs > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} unreachable inputs from method {2}", removedInputs, initialInputsSize, this.name));
        initialInputsSize = this.groupsOfOccurrences.size();
        this.groupsOfOccurrences.removeIf(groupOfOccurrence -> groupOfOccurrence.getMetrics().getTtl() == 0);
        removedInputs = initialInputsSize - this.groupsOfOccurrences.size();
        if (removedInputs > 0) LOGGER.info(MessageFormat.format("\tRemoved {0} of {1} inputs with 0 TTL from method {2}", removedInputs, initialInputsSize, this.name));
    }

    @Override
    public String toString() {
        return this.name;
    }

}