Method.java

135 lines | 4.548 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.aplcache.metadata;

import br.ufrgs.inf.prosoft.aplcache.flowchart.metrics.CacheabilityPatternDecider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

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

    private static final Logger LOGGER = Logger.getLogger(Method.class.getName());
    private static final boolean TRACER_VERBOSE = System.getenv("TRACER_VERBOSE") != null && System.getenv("TRACER_VERBOSE").equals("true");

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

    public Method(String name) {
        this.name = name;
        this.occurrences = new ArrayList<>();
    }

    public Method(String name, List<Occurrence> occurrences) {
        this.name = name;
        this.occurrences = occurrences;
    }

    public String getName() {
        return name;
    }

    public Method addOccurrence(Occurrence occurrence) {
        this.occurrences.add(occurrence);
        return this;
    }

    public int getOccurrencesSize() {
        return this.occurrences.size();
    }

    public Stream<Occurrence> occurrences() {
        if (this.occurrences == null) {
            throw new RuntimeException("Occurrences already consumed");
        }
        return this.occurrences.stream();
    }

    public Stream<GroupOfOccurrences> groupsOfOccurrences() {
        return this.groupsOfOccurrences.stream();
    }

    private void groupByInput() {
        LOGGER.log(Level.FINE, "Grouping by parameters {0} occurrences of {1}", new Object[]{this.name, this.occurrences.size()});
        Map<String, GroupOfOccurrences> groupByParameter = new HashMap<>();
        this.occurrences.stream().parallel().forEach(new Consumer<Occurrence>() {

            private int i;

            {
                this.i = 0;
            }

            @Override
            public void accept(Occurrence occurrence) {
                if (TRACER_VERBOSE) {
                    System.out.print(".");
                    System.out.flush();
                    if (++this.i % 100 == 0) {
                        System.out.println();
                    }
                }
                String parameters = occurrence.getParametersSerialised();
                synchronized (groupByParameter) {
                    try {
                        groupByParameter.get(parameters).addOccurrence(occurrence);
                    } catch (Exception e) {
                        GroupOfOccurrences groupOfOccurrences = new GroupOfOccurrences(parameters);
                        groupOfOccurrences.addOccurrence(occurrence);
                        groupByParameter.put(parameters, groupOfOccurrences);
                    }
                }
            }
        });
        this.groupsOfOccurrences = groupByParameter.values().stream().collect(Collectors.toList());
    }

    public void removeSingleOccurrences() {
        if (this.groupsOfOccurrences == null) {
            groupByInput();
        }
        int initialCountofOccurrences = this.groupsOfOccurrences.size();
        this.groupsOfOccurrences.removeIf(groupOfOccurrences -> groupOfOccurrences.getOccurrencesSize() < 2);
        int removedOccurrences = initialCountofOccurrences - this.groupsOfOccurrences.size();
        if (removedOccurrences > 0) {
            LOGGER.log(Level.INFO, "\tRemoved {0} of {1} inputs from method {2}", new Object[]{removedOccurrences, initialCountofOccurrences, this.name});
        }
    }

    public void calculateMetrics() {
        if (this.groupsOfOccurrences == null) {
            groupByInput();
        }
        Collections.sort(this.groupsOfOccurrences, (g1, g2) -> Integer.compare(g1.getOccurrencesSize(), g2.getOccurrencesSize()));
        this.groupsOfOccurrences.stream().parallel().forEach(GroupOfOccurrences::calculateMetrics);
    }

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

    public void filterCacheableInputs() {
        this.groupsOfOccurrences.removeIf(CacheabilityPatternDecider::isNotCacheable);
    }

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