001package daikon.tools;
002
003import daikon.FileIO;
004import daikon.PptMap;
005import daikon.PptTopLevel;
006import daikon.ValueTuple;
007import daikon.VarInfo;
008import java.util.ArrayList;
009import java.util.Arrays;
010import java.util.LinkedHashMap;
011import java.util.List;
012import java.util.Map;
013import org.checkerframework.checker.nullness.qual.Nullable;
014import org.checkerframework.checker.nullness.qual.RequiresNonNull;
015
016/**
017 * A class that gives an example of how to use a FileIO.Processor object to read a trace file.
018 * Invoke it like:
019 *
020 * <pre>
021 *   java daikon.tools.ReadTrace file1 file2 ...
022 * </pre>
023 *
024 * A concrete example invocation:
025 *
026 * <pre>
027 *   java -cp $DAIKONDIR/daikon.jar daikon.tools.ReadTrace /scratch/$USER/tests/daikon-tests/StackAr/StackAr.dtrace.gz
028 * </pre>
029 *
030 * You probably won't run this program. Instead, you will copy parts of its source code in the
031 * process of writing your own program that reads a dtrace file.
032 */
033public class ReadTrace {
034
035  /** Do not instantiate. */
036  private ReadTrace() {
037    throw new Error("Do not instantiate");
038  }
039
040  /**
041   * The entry point for ReadTrace.
042   *
043   * @param args data trace file names, read from the command line
044   */
045  public static void main(String[] args) {
046    CollectDataProcessor processor = new CollectDataProcessor();
047    PptMap ppts = new PptMap();
048    try {
049      // `read_data_trace_files()` requires the list of files to be modifiable.
050      FileIO.read_data_trace_files(new ArrayList<>(Arrays.asList(args)), ppts, processor, false);
051    } catch (Exception e) {
052      throw new Error(e);
053    }
054
055    // At this point, the processor has been called on each sample in turn.
056    // Now, we can do whatever we like with the data.
057
058    for (PptTopLevel ppt : processor.samples.keySet()) {
059      for (ValueTuple vt : processor.samples.get(ppt)) {
060        System.out.printf("%nSample for %s :%n", ppt.name());
061        for (VarInfo vi : ppt.var_infos) {
062          System.out.printf("%s = %s%n", vi.name(), vt.getValueOrNull(vi));
063        }
064      }
065    }
066  }
067
068  /**
069   * Populates the {@code samples} map with all the data read from the file. This is only reasonable
070   * for small trace files, since all the data will be retained in memory!
071   */
072  public static class CollectDataProcessor extends FileIO.Processor {
073
074    public Map<PptTopLevel, List<ValueTuple>> samples = new LinkedHashMap<>();
075
076    /** Process the sample, by adding it to the {@code samples} map. */
077    @RequiresNonNull("daikon.FileIO.data_trace_state")
078    @Override
079    public void process_sample(
080        PptMap all_ppts, PptTopLevel ppt, ValueTuple vt, @Nullable Integer nonce) {
081
082      // Add orig and derived variables to the ValueTuple
083      FileIO.compute_orig_variables(ppt, vt.vals, vt.mods, nonce);
084      FileIO.compute_derived_variables(ppt, vt.vals, vt.mods);
085
086      // Intern the sample, to save space, since we are storing them all.
087      vt = new ValueTuple(vt.vals, vt.mods);
088
089      // Add the sample to the map
090      if (!samples.containsKey(ppt)) {
091        samples.put(ppt, new ArrayList<ValueTuple>());
092      }
093      samples.get(ppt).add(vt);
094    }
095  }
096}