예제 #1
0
  @Override
  public void verify(QueryContext context, String queryString) {
    if (!context.getSession().isAdmin()) throw new QueryParseException("95050", -1, -1, null);

    ThreadMXBean bean = ManagementFactory.getThreadMXBean();
    if (!bean.isThreadCpuTimeSupported()) throw new QueryParseException("95051", -1, -1, null);

    if (!bean.isThreadCpuTimeEnabled()) throw new QueryParseException("95051", -1, -1, null);
  }
예제 #2
0
 /**
  * Prints the cpu time for the given thread, i.e. the time the thread was effectively active on
  * the CPU.
  *
  * @param thread
  */
 public static final void printThreadCpuTime(final Thread thread) {
   if (tbe.isThreadCpuTimeEnabled()) {
     log.info(
         "Thread performance: Thread="
             + thread.getName()
             + "  cpu-time="
             + getThreadCpuTime(thread)
             + "sec");
   }
 }
예제 #3
0
  public void testTakeCPUTime() {
    ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
    if (!mbean.isThreadCpuTimeEnabled()) {
      fail("ThreadMXBean CPU time reporting is not enabled");
    }

    long msecMultiplier = 1000 * 1000;
    long msecGoal = 10;
    long cpuGoal = msecGoal * msecMultiplier;

    long beforeCPU = mbean.getCurrentThreadCpuTime();
    MyMetricFunctions.takeCPUTime(cpuGoal);
    long afterCPU = mbean.getCurrentThreadCpuTime();
    assertTrue((afterCPU - beforeCPU) > cpuGoal);
  }
예제 #4
0
 /**
  * @param thread
  * @return cpu time for the given thread in seconds, <code>-1</code> if cpu time is not measured.
  */
 public static final double getThreadCpuTime(final Thread thread) {
   if (tbe.isThreadCpuTimeEnabled()) {
     return tbe.getThreadCpuTime(thread.getId()) / 1.0e9;
   }
   return -1;
 }
예제 #5
0
  /**
   * Retrieve a JVM information text formatted using the given StringManager.
   *
   * @param requestedSm the StringManager to use
   * @return the formatted JVM information text
   */
  private static String getVMInfo(StringManager requestedSm) {
    StringBuilder sb = new StringBuilder();

    synchronized (timeformat) {
      sb.append(timeformat.format(new Date()));
    }
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoRuntime"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "vmName: " + runtimeMXBean.getVmName() + CRLF);
    sb.append(INDENT1 + "vmVersion: " + runtimeMXBean.getVmVersion() + CRLF);
    sb.append(INDENT1 + "vmVendor: " + runtimeMXBean.getVmVendor() + CRLF);
    sb.append(INDENT1 + "specName: " + runtimeMXBean.getSpecName() + CRLF);
    sb.append(INDENT1 + "specVersion: " + runtimeMXBean.getSpecVersion() + CRLF);
    sb.append(INDENT1 + "specVendor: " + runtimeMXBean.getSpecVendor() + CRLF);
    sb.append(
        INDENT1 + "managementSpecVersion: " + runtimeMXBean.getManagementSpecVersion() + CRLF);
    sb.append(INDENT1 + "name: " + runtimeMXBean.getName() + CRLF);
    sb.append(INDENT1 + "startTime: " + runtimeMXBean.getStartTime() + CRLF);
    sb.append(INDENT1 + "uptime: " + runtimeMXBean.getUptime() + CRLF);
    sb.append(
        INDENT1 + "isBootClassPathSupported: " + runtimeMXBean.isBootClassPathSupported() + CRLF);
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoOs"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "name: " + operatingSystemMXBean.getName() + CRLF);
    sb.append(INDENT1 + "version: " + operatingSystemMXBean.getVersion() + CRLF);
    sb.append(INDENT1 + "architecture: " + operatingSystemMXBean.getArch() + CRLF);
    sb.append(
        INDENT1 + "availableProcessors: " + operatingSystemMXBean.getAvailableProcessors() + CRLF);
    sb.append(
        INDENT1 + "systemLoadAverage: " + operatingSystemMXBean.getSystemLoadAverage() + CRLF);
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoThreadMxBean"));
    sb.append(":" + CRLF);
    sb.append(
        INDENT1
            + "isCurrentThreadCpuTimeSupported: "
            + threadMXBean.isCurrentThreadCpuTimeSupported()
            + CRLF);
    sb.append(
        INDENT1 + "isThreadCpuTimeSupported: " + threadMXBean.isThreadCpuTimeSupported() + CRLF);
    sb.append(INDENT1 + "isThreadCpuTimeEnabled: " + threadMXBean.isThreadCpuTimeEnabled() + CRLF);
    sb.append(
        INDENT1
            + "isObjectMonitorUsageSupported: "
            + threadMXBean.isObjectMonitorUsageSupported()
            + CRLF);
    sb.append(
        INDENT1
            + "isSynchronizerUsageSupported: "
            + threadMXBean.isSynchronizerUsageSupported()
            + CRLF);
    sb.append(
        INDENT1
            + "isThreadContentionMonitoringSupported: "
            + threadMXBean.isThreadContentionMonitoringSupported()
            + CRLF);
    sb.append(
        INDENT1
            + "isThreadContentionMonitoringEnabled: "
            + threadMXBean.isThreadContentionMonitoringEnabled()
            + CRLF);
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoThreadCounts"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "daemon: " + threadMXBean.getDaemonThreadCount() + CRLF);
    sb.append(INDENT1 + "total: " + threadMXBean.getThreadCount() + CRLF);
    sb.append(INDENT1 + "peak: " + threadMXBean.getPeakThreadCount() + CRLF);
    sb.append(INDENT1 + "totalStarted: " + threadMXBean.getTotalStartedThreadCount() + CRLF);
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoStartup"));
    sb.append(":" + CRLF);
    for (String arg : runtimeMXBean.getInputArguments()) {
      sb.append(INDENT1 + arg + CRLF);
    }
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoPath"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "bootClassPath: " + runtimeMXBean.getBootClassPath() + CRLF);
    sb.append(INDENT1 + "classPath: " + runtimeMXBean.getClassPath() + CRLF);
    sb.append(INDENT1 + "libraryPath: " + runtimeMXBean.getLibraryPath() + CRLF);
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoClassLoading"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "loaded: " + classLoadingMXBean.getLoadedClassCount() + CRLF);
    sb.append(INDENT1 + "unloaded: " + classLoadingMXBean.getUnloadedClassCount() + CRLF);
    sb.append(INDENT1 + "totalLoaded: " + classLoadingMXBean.getTotalLoadedClassCount() + CRLF);
    sb.append(INDENT1 + "isVerbose: " + classLoadingMXBean.isVerbose() + CRLF);
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoClassCompilation"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "name: " + compilationMXBean.getName() + CRLF);
    sb.append(
        INDENT1 + "totalCompilationTime: " + compilationMXBean.getTotalCompilationTime() + CRLF);
    sb.append(
        INDENT1
            + "isCompilationTimeMonitoringSupported: "
            + compilationMXBean.isCompilationTimeMonitoringSupported()
            + CRLF);
    sb.append(CRLF);

    for (MemoryManagerMXBean mbean : memoryManagerMXBeans) {
      sb.append(requestedSm.getString("diagnostics.vmInfoMemoryManagers", mbean.getName()));
      sb.append(":" + CRLF);
      sb.append(INDENT1 + "isValid: " + mbean.isValid() + CRLF);
      sb.append(INDENT1 + "mbean.getMemoryPoolNames: " + CRLF);
      String[] names = mbean.getMemoryPoolNames();
      Arrays.sort(names);
      for (String name : names) {
        sb.append(INDENT2 + name + CRLF);
      }
      sb.append(CRLF);
    }

    for (GarbageCollectorMXBean mbean : garbageCollectorMXBeans) {
      sb.append(requestedSm.getString("diagnostics.vmInfoGarbageCollectors", mbean.getName()));
      sb.append(":" + CRLF);
      sb.append(INDENT1 + "isValid: " + mbean.isValid() + CRLF);
      sb.append(INDENT1 + "mbean.getMemoryPoolNames: " + CRLF);
      String[] names = mbean.getMemoryPoolNames();
      Arrays.sort(names);
      for (String name : names) {
        sb.append(INDENT2 + name + CRLF);
      }
      sb.append(INDENT1 + "getCollectionCount: " + mbean.getCollectionCount() + CRLF);
      sb.append(INDENT1 + "getCollectionTime: " + mbean.getCollectionTime() + CRLF);
      sb.append(CRLF);
    }

    sb.append(requestedSm.getString("diagnostics.vmInfoMemory"));
    sb.append(":" + CRLF);
    sb.append(INDENT1 + "isVerbose: " + memoryMXBean.isVerbose() + CRLF);
    sb.append(
        INDENT1
            + "getObjectPendingFinalizationCount: "
            + memoryMXBean.getObjectPendingFinalizationCount()
            + CRLF);
    sb.append(formatMemoryUsage("heap", memoryMXBean.getHeapMemoryUsage()));
    sb.append(formatMemoryUsage("non-heap", memoryMXBean.getNonHeapMemoryUsage()));
    sb.append(CRLF);

    for (MemoryPoolMXBean mbean : memoryPoolMXBeans) {
      sb.append(requestedSm.getString("diagnostics.vmInfoMemoryPools", mbean.getName()));
      sb.append(":" + CRLF);
      sb.append(INDENT1 + "isValid: " + mbean.isValid() + CRLF);
      sb.append(INDENT1 + "getType: " + mbean.getType() + CRLF);
      sb.append(INDENT1 + "mbean.getMemoryManagerNames: " + CRLF);
      String[] names = mbean.getMemoryManagerNames();
      Arrays.sort(names);
      for (String name : names) {
        sb.append(INDENT2 + name + CRLF);
      }
      sb.append(INDENT1 + "isUsageThresholdSupported: " + mbean.isUsageThresholdSupported() + CRLF);
      try {
        sb.append(INDENT1 + "isUsageThresholdExceeded: " + mbean.isUsageThresholdExceeded() + CRLF);
      } catch (UnsupportedOperationException ex) {
        // IGNORE
      }
      sb.append(
          INDENT1
              + "isCollectionUsageThresholdSupported: "
              + mbean.isCollectionUsageThresholdSupported()
              + CRLF);
      try {
        sb.append(
            INDENT1
                + "isCollectionUsageThresholdExceeded: "
                + mbean.isCollectionUsageThresholdExceeded()
                + CRLF);
      } catch (UnsupportedOperationException ex) {
        // IGNORE
      }
      try {
        sb.append(INDENT1 + "getUsageThreshold: " + mbean.getUsageThreshold() + CRLF);
      } catch (UnsupportedOperationException ex) {
        // IGNORE
      }
      try {
        sb.append(INDENT1 + "getUsageThresholdCount: " + mbean.getUsageThresholdCount() + CRLF);
      } catch (UnsupportedOperationException ex) {
        // IGNORE
      }
      try {
        sb.append(
            INDENT1 + "getCollectionUsageThreshold: " + mbean.getCollectionUsageThreshold() + CRLF);
      } catch (UnsupportedOperationException ex) {
        // IGNORE
      }
      try {
        sb.append(
            INDENT1
                + "getCollectionUsageThresholdCount: "
                + mbean.getCollectionUsageThresholdCount()
                + CRLF);
      } catch (UnsupportedOperationException ex) {
        // IGNORE
      }
      sb.append(formatMemoryUsage("current", mbean.getUsage()));
      sb.append(formatMemoryUsage("collection", mbean.getCollectionUsage()));
      sb.append(formatMemoryUsage("peak", mbean.getPeakUsage()));
      sb.append(CRLF);
    }

    sb.append(requestedSm.getString("diagnostics.vmInfoSystem"));
    sb.append(":" + CRLF);
    Map<String, String> props = runtimeMXBean.getSystemProperties();
    ArrayList<String> keys = new ArrayList<String>(props.keySet());
    Collections.sort(keys);
    for (String prop : keys) {
      sb.append(INDENT1 + prop + ": " + props.get(prop) + CRLF);
    }
    sb.append(CRLF);

    sb.append(requestedSm.getString("diagnostics.vmInfoLogger"));
    sb.append(":" + CRLF);
    List<String> loggers = loggingMXBean.getLoggerNames();
    Collections.sort(loggers);
    for (String logger : loggers) {
      sb.append(
          INDENT1
              + logger
              + ": level="
              + loggingMXBean.getLoggerLevel(logger)
              + ", parent="
              + loggingMXBean.getParentLoggerName(logger)
              + CRLF);
    }
    sb.append(CRLF);

    return sb.toString();
  }
예제 #6
0
  /**
   * Gets the results for the supplied train and test datasets. Now performs a deep copy of the
   * classifier before it is built and evaluated (just in case the classifier is not initialized
   * properly in buildClassifier()).
   *
   * @param train the training Instances.
   * @param test the testing Instances.
   * @return the results stored in an array. The objects stored in the array may be Strings,
   *     Doubles, or null (for the missing value).
   * @throws Exception if a problem occurs while getting the results
   */
  public Object[] getResult(Instances train, Instances test) throws Exception {

    if (train.classAttribute().type() != Attribute.NUMERIC) {
      throw new Exception("Class attribute is not numeric!");
    }
    if (m_Template == null) {
      throw new Exception("No classifier has been specified");
    }
    ThreadMXBean thMonitor = ManagementFactory.getThreadMXBean();
    boolean canMeasureCPUTime = thMonitor.isThreadCpuTimeSupported();
    if (canMeasureCPUTime && !thMonitor.isThreadCpuTimeEnabled())
      thMonitor.setThreadCpuTimeEnabled(true);

    int addm = (m_AdditionalMeasures != null) ? m_AdditionalMeasures.length : 0;
    Object[] result = new Object[RESULT_SIZE + addm + m_numPluginStatistics];
    long thID = Thread.currentThread().getId();
    long CPUStartTime = -1,
        trainCPUTimeElapsed = -1,
        testCPUTimeElapsed = -1,
        trainTimeStart,
        trainTimeElapsed,
        testTimeStart,
        testTimeElapsed;
    Evaluation eval = new Evaluation(train);
    m_Classifier = AbstractClassifier.makeCopy(m_Template);

    trainTimeStart = System.currentTimeMillis();
    if (canMeasureCPUTime) CPUStartTime = thMonitor.getThreadUserTime(thID);
    m_Classifier.buildClassifier(train);
    if (canMeasureCPUTime) trainCPUTimeElapsed = thMonitor.getThreadUserTime(thID) - CPUStartTime;
    trainTimeElapsed = System.currentTimeMillis() - trainTimeStart;
    testTimeStart = System.currentTimeMillis();
    if (canMeasureCPUTime) CPUStartTime = thMonitor.getThreadUserTime(thID);
    eval.evaluateModel(m_Classifier, test);
    if (canMeasureCPUTime) testCPUTimeElapsed = thMonitor.getThreadUserTime(thID) - CPUStartTime;
    testTimeElapsed = System.currentTimeMillis() - testTimeStart;
    thMonitor = null;

    m_result = eval.toSummaryString();
    // The results stored are all per instance -- can be multiplied by the
    // number of instances to get absolute numbers
    int current = 0;
    result[current++] = new Double(train.numInstances());
    result[current++] = new Double(eval.numInstances());

    result[current++] = new Double(eval.meanAbsoluteError());
    result[current++] = new Double(eval.rootMeanSquaredError());
    result[current++] = new Double(eval.relativeAbsoluteError());
    result[current++] = new Double(eval.rootRelativeSquaredError());
    result[current++] = new Double(eval.correlationCoefficient());

    result[current++] = new Double(eval.SFPriorEntropy());
    result[current++] = new Double(eval.SFSchemeEntropy());
    result[current++] = new Double(eval.SFEntropyGain());
    result[current++] = new Double(eval.SFMeanPriorEntropy());
    result[current++] = new Double(eval.SFMeanSchemeEntropy());
    result[current++] = new Double(eval.SFMeanEntropyGain());

    // Timing stats
    result[current++] = new Double(trainTimeElapsed / 1000.0);
    result[current++] = new Double(testTimeElapsed / 1000.0);
    if (canMeasureCPUTime) {
      result[current++] = new Double((trainCPUTimeElapsed / 1000000.0) / 1000.0);
      result[current++] = new Double((testCPUTimeElapsed / 1000000.0) / 1000.0);
    } else {
      result[current++] = new Double(Utils.missingValue());
      result[current++] = new Double(Utils.missingValue());
    }

    // sizes
    if (m_NoSizeDetermination) {
      result[current++] = -1.0;
      result[current++] = -1.0;
      result[current++] = -1.0;
    } else {
      ByteArrayOutputStream bastream = new ByteArrayOutputStream();
      ObjectOutputStream oostream = new ObjectOutputStream(bastream);
      oostream.writeObject(m_Classifier);
      result[current++] = new Double(bastream.size());
      bastream = new ByteArrayOutputStream();
      oostream = new ObjectOutputStream(bastream);
      oostream.writeObject(train);
      result[current++] = new Double(bastream.size());
      bastream = new ByteArrayOutputStream();
      oostream = new ObjectOutputStream(bastream);
      oostream.writeObject(test);
      result[current++] = new Double(bastream.size());
    }

    // Prediction interval statistics
    result[current++] = new Double(eval.coverageOfTestCasesByPredictedRegions());
    result[current++] = new Double(eval.sizeOfPredictedRegions());

    if (m_Classifier instanceof Summarizable) {
      result[current++] = ((Summarizable) m_Classifier).toSummaryString();
    } else {
      result[current++] = null;
    }

    for (int i = 0; i < addm; i++) {
      if (m_doesProduce[i]) {
        try {
          double dv =
              ((AdditionalMeasureProducer) m_Classifier).getMeasure(m_AdditionalMeasures[i]);
          if (!Utils.isMissingValue(dv)) {
            Double value = new Double(dv);
            result[current++] = value;
          } else {
            result[current++] = null;
          }
        } catch (Exception ex) {
          System.err.println(ex);
        }
      } else {
        result[current++] = null;
      }
    }

    // get the actual metrics from the evaluation object
    List<AbstractEvaluationMetric> metrics = eval.getPluginMetrics();
    if (metrics != null) {
      for (AbstractEvaluationMetric m : metrics) {
        if (m.appliesToNumericClass()) {
          List<String> statNames = m.getStatisticNames();
          for (String s : statNames) {
            result[current++] = new Double(m.getStatistic(s));
          }
        }
      }
    }

    if (current != RESULT_SIZE + addm + m_numPluginStatistics) {
      throw new Error("Results didn't fit RESULT_SIZE");
    }
    return result;
  }
예제 #7
0
  private String innerDetect() throws Exception {
    StringBuilder sb = new StringBuilder();

    sb.append("Hot threads at ");
    sb.append(DATE_TIME_FORMATTER.printer().print(System.currentTimeMillis()));
    sb.append(", interval=");
    sb.append(interval);
    sb.append(", busiestThreads=");
    sb.append(busiestThreads);
    sb.append(", ignoreIdleThreads=");
    sb.append(ignoreIdleThreads);
    sb.append(":\n");

    ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
    boolean enabledCpu = false;
    try {
      if (threadBean.isThreadCpuTimeSupported()) {
        if (!threadBean.isThreadCpuTimeEnabled()) {
          enabledCpu = true;
          threadBean.setThreadCpuTimeEnabled(true);
        }
      } else {
        throw new IllegalStateException("MBean doesn't support thread CPU Time");
      }
      Map<Long, MyThreadInfo> threadInfos = new HashMap<>();
      for (long threadId : threadBean.getAllThreadIds()) {
        // ignore our own thread...
        if (Thread.currentThread().getId() == threadId) {
          continue;
        }
        long cpu = threadBean.getThreadCpuTime(threadId);
        if (cpu == -1) {
          continue;
        }
        ThreadInfo info = threadBean.getThreadInfo(threadId, 0);
        if (info == null) {
          continue;
        }
        threadInfos.put(threadId, new MyThreadInfo(cpu, info));
      }
      Thread.sleep(interval.millis());
      for (long threadId : threadBean.getAllThreadIds()) {
        // ignore our own thread...
        if (Thread.currentThread().getId() == threadId) {
          continue;
        }
        long cpu = threadBean.getThreadCpuTime(threadId);
        if (cpu == -1) {
          threadInfos.remove(threadId);
          continue;
        }
        ThreadInfo info = threadBean.getThreadInfo(threadId, 0);
        if (info == null) {
          threadInfos.remove(threadId);
          continue;
        }
        MyThreadInfo data = threadInfos.get(threadId);
        if (data != null) {
          data.setDelta(cpu, info);
        } else {
          threadInfos.remove(threadId);
        }
      }
      // sort by delta CPU time on thread.
      List<MyThreadInfo> hotties = new ArrayList<>(threadInfos.values());
      final int busiestThreads = Math.min(this.busiestThreads, hotties.size());
      // skip that for now
      CollectionUtil.introSort(
          hotties,
          new Comparator<MyThreadInfo>() {
            @Override
            public int compare(MyThreadInfo o1, MyThreadInfo o2) {
              if ("cpu".equals(type)) {
                return (int) (o2.cpuTime - o1.cpuTime);
              } else if ("wait".equals(type)) {
                return (int) (o2.waitedTime - o1.waitedTime);
              } else if ("block".equals(type)) {
                return (int) (o2.blockedTime - o1.blockedTime);
              }
              throw new IllegalArgumentException();
            }
          });
      // analyse N stack traces for M busiest threads
      long[] ids = new long[busiestThreads];
      for (int i = 0; i < busiestThreads; i++) {
        MyThreadInfo info = hotties.get(i);
        ids[i] = info.info.getThreadId();
      }
      ThreadInfo[][] allInfos = new ThreadInfo[threadElementsSnapshotCount][];
      for (int j = 0; j < threadElementsSnapshotCount; j++) {
        // NOTE, javadoc of getThreadInfo says: If a thread of the given ID is not alive or does not
        // exist,
        // null will be set in the corresponding element in the returned array. A thread is alive if
        // it has
        // been started and has not yet died.
        allInfos[j] = threadBean.getThreadInfo(ids, Integer.MAX_VALUE);
        Thread.sleep(threadElementsSnapshotDelay.millis());
      }
      for (int t = 0; t < busiestThreads; t++) {
        long time = 0;
        if ("cpu".equals(type)) {
          time = hotties.get(t).cpuTime;
        } else if ("wait".equals(type)) {
          time = hotties.get(t).waitedTime;
        } else if ("block".equals(type)) {
          time = hotties.get(t).blockedTime;
        }
        String threadName = null;
        for (ThreadInfo[] info : allInfos) {
          if (info != null && info[t] != null) {
            if (ignoreIdleThreads && isIdleThread(info[t])) {
              info[t] = null;
              continue;
            }
            threadName = info[t].getThreadName();
            break;
          }
        }
        if (threadName == null) {
          continue; // thread is not alive yet or died before the first snapshot - ignore it!
        }
        double percent = (((double) time) / interval.nanos()) * 100;
        sb.append(
            String.format(
                Locale.ROOT,
                "%n%4.1f%% (%s out of %s) %s usage by thread '%s'%n",
                percent,
                TimeValue.timeValueNanos(time),
                interval,
                type,
                threadName));
        // for each snapshot (2nd array index) find later snapshot for same thread with max number
        // of
        // identical StackTraceElements (starting from end of each)
        boolean[] done = new boolean[threadElementsSnapshotCount];
        for (int i = 0; i < threadElementsSnapshotCount; i++) {
          if (done[i]) continue;
          int maxSim = 1;
          boolean[] similars = new boolean[threadElementsSnapshotCount];
          for (int j = i + 1; j < threadElementsSnapshotCount; j++) {
            if (done[j]) continue;
            int similarity = similarity(allInfos[i][t], allInfos[j][t]);
            if (similarity > maxSim) {
              maxSim = similarity;
              similars = new boolean[threadElementsSnapshotCount];
            }
            if (similarity == maxSim) similars[j] = true;
          }
          // print out trace maxSim levels of i, and mark similar ones as done
          int count = 1;
          for (int j = i + 1; j < threadElementsSnapshotCount; j++) {
            if (similars[j]) {
              done[j] = true;
              count++;
            }
          }
          if (allInfos[i][t] != null) {
            final StackTraceElement[] show = allInfos[i][t].getStackTrace();
            if (count == 1) {
              sb.append(String.format(Locale.ROOT, "  unique snapshot%n"));
              for (int l = 0; l < show.length; l++) {
                sb.append(String.format(Locale.ROOT, "    %s%n", show[l]));
              }
            } else {
              sb.append(
                  String.format(
                      Locale.ROOT,
                      "  %d/%d snapshots sharing following %d elements%n",
                      count,
                      threadElementsSnapshotCount,
                      maxSim));
              for (int l = show.length - maxSim; l < show.length; l++) {
                sb.append(String.format(Locale.ROOT, "    %s%n", show[l]));
              }
            }
          }
        }
      }
      return sb.toString();
    } finally {
      if (enabledCpu) {
        threadBean.setThreadCpuTimeEnabled(false);
      }
    }
  }