/** Returns this PerfStatValue divided by the argument, field by field. */
  public PerfStatValue dividedBy(PerfStatValue dpsv) {
    PerfStatValue psv = new PerfStatValue(this.statspec, this.trimspec);
    if (this.isFlatline() && dpsv.isFlatline()) {
      return null;
    }

    psv.setArchives(this.archives);
    psv.setProductVersion(this.productVersion);
    psv.setIsLargerBetter(this.isLargerBetter); // go with the numerator here
    psv.setSamples(this.samples.intValue());

    if (this.min != null && dpsv.min != null) {
      psv.setMin(divide(this.getMin(), dpsv.getMin()));
    }
    if (this.max != null && dpsv.max != null) {
      psv.setMax(divide(this.getMax(), dpsv.getMax()));
    }
    if (this.maxminusmin != null && dpsv.maxminusmin != null) {
      psv.setMaxMinusMin(divide(this.getMaxMinusMin(), dpsv.getMaxMinusMin()));
    }
    if (this.mean != null && dpsv.mean != null) {
      psv.setMean(divide(this.getMean(), dpsv.getMean()));
    }
    if (this.stddev != null && dpsv.stddev != null) {
      psv.setStddev(divide(this.getStddev(), dpsv.getStddev()));
    }
    return psv;
  }
  /**
   * Translates a StatValue into a PerfStatValue with the specified filter, with the specified
   * operations, and the specified trim. For the latter, if start is -1, uses the beginning of the
   * statistic's existence, and if end is -1, goes to the end of the statistic's existence.
   */
  protected static PerfStatValue getPerfStatValue(
      StatSpec statspec, TrimSpec trimspec, StatArchiveReader.StatValue sv) {
    long start = trimspec.getStart();
    long end = trimspec.getEnd();
    sv = sv.createTrimmed(start, end);
    if (Log.getLogWriter().finestEnabled()) {
      Log.getLogWriter()
          .finest(
              "PerfStatReader: Trimmed from "
                  + trimspec.getStartStr()
                  + " ("
                  + start
                  + ") to "
                  + trimspec.getEndStr()
                  + " ("
                  + end
                  + ")");
    }

    int filter = statspec.getFilter();
    double mean = -1;
    if (filter == StatArchiveReader.StatValue.FILTER_PERSEC && statspec.getMean()) {
      if (start == -1) {
        start = sv.getRawAbsoluteTimeStamps()[0];
      }
      if (end == -1) {
        long[] rats = sv.getRawAbsoluteTimeStamps();
        end = rats[rats.length - 1];
      }
      long elapsedSec = (end - start) / 1000;
      sv.setFilter(StatArchiveReader.StatValue.FILTER_NONE);
      double del = sv.getSnapshotsMaximum() - sv.getSnapshotsMinimum();
      mean = del / elapsedSec;
    }
    sv.setFilter(filter);

    // @todo lises see if psv really needs to hang onto specs
    PerfStatValue psv = new PerfStatValue(statspec, trimspec);
    psv.setIsLargerBetter(sv.getDescriptor().isLargerBetter());
    psv.setSamples(sv.getSnapshotsSize());

    if (statspec.getMin()) psv.setMin(sv.getSnapshotsMinimum());
    if (statspec.getMax()) psv.setMax(sv.getSnapshotsMaximum());
    if (statspec.getMaxMinusMin())
      psv.setMaxMinusMin(sv.getSnapshotsMaximum() - sv.getSnapshotsMinimum());
    if (statspec.getMean()) {
      if (filter == StatArchiveReader.StatValue.FILTER_PERSEC) {
        psv.setMean(mean);
      } else {
        psv.setMean(sv.getSnapshotsAverage());
      }
    }
    if (statspec.getStddev()) psv.setStddev(sv.getSnapshotsStandardDeviation());

    SortedSet archives = new TreeSet();
    StatArchiveReader.ResourceInst[] resources = sv.getResources();
    String productVersion = null;
    for (int i = 0; i < resources.length; i++) {
      String archive = resources[i].getArchive().getFile().getParentFile().getName();
      if (productVersion == null) {
        productVersion = resources[i].getArchive().getArchiveInfo().getProductVersion();
      }
      if (!archives.contains(archive)) {
        archives.add(archive);
      }
    }
    psv.setArchives(archives);
    psv.setProductVersion(productVersion);

    return psv;
  }