All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.apphosting.runtime.timer.CpuRatioTimer Maven / Gradle / Ivy

/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.apphosting.runtime.timer;

import java.util.Arrays;

/**
 * {@code CpuRatioTimer} is a composite {@code Timer} that is backed
 * by two other {@code Timer} objects -- e.g. one that measures CPU
 * time and one that measures wallclock time.  When started or
 * stopped, it will start and stop both underlying {@code Timer}
 * objects.
 *
 * It also exposes additional methods to calculate a CPU usage ratio
 * and cycle count (calculated from the CPU time and a {@code
 * CpuSpeedExtractor}).
 *
 */
public class CpuRatioTimer implements Timer {
  private final Timer cpuUsageTimer;
  private final Timer wallclockTimer;
  private final CpuSpeedExtractor cpuSpeedExtractor;
  private final Timer[] extraTimers;

  /**
   * Create a new {@link CpuRatioTimer}.
   *
   * @param cpuUsageTimer Tracks the CPU time used by the request.
   * @param wallclockTimer Tracks the total elapsed time of the request.
   * @param cpuSpeedExtractor converts CPU time to CPU cycles
   * @param extraTimers includes timers for background work that is
   * added to the total return value of this timer (but do not affect
   * the CPU ratio).
   */
  public CpuRatioTimer(
      Timer cpuUsageTimer,
      Timer wallclockTimer,
      CpuSpeedExtractor cpuSpeedExtractor,
      Timer[] extraTimers) {
    this.cpuUsageTimer = cpuUsageTimer;
    this.wallclockTimer = wallclockTimer;
    this.cpuSpeedExtractor = cpuSpeedExtractor;
    this.extraTimers = extraTimers;
  }

  /**
   * Start both timers.
   */
  @Override
  public void start() {
    cpuUsageTimer.start();
    wallclockTimer.start();
    for (Timer timer : extraTimers) {
      timer.start();
    }
  }

  /**
   * Stop both timers.
   */
  @Override
  public void stop() {
    cpuUsageTimer.stop();
    wallclockTimer.stop();
    for (Timer timer : extraTimers) {
      timer.stop();
    }
  }

  @Override
  public void update() {
    cpuUsageTimer.update();
    wallclockTimer.update();
    for (Timer timer : extraTimers) {
      timer.update();
    }
  }

  /**
   * Returns the underlying CPU usage {@code Timer}.
   */
  public Timer getCpuUsageTimer() {
    return cpuUsageTimer;
  }

  /**
   * Returns the underlying wallclock {@code Timer}.
   */
  public Timer getWallclockTimer() {
    return wallclockTimer;
  }

  /**
   * Returns a ratio (between 0 and 1) that represents the percentage
   * of elapsed wallclock time which was spent executing CPU
   * instructions.
   */
  public double getCpuRatio() {
    double cpuNanos = cpuUsageTimer.getNanoseconds();
    double wallclockNanos = wallclockTimer.getNanoseconds();
    return cpuNanos / wallclockNanos;
  }

  /**
   * Convert the number of CPU seconds elapsed into a CPU cycle count
   * using the CPU speed reported by the {@code CpuSpeedExtractor}.
   * This value also includes a fraction of hotspot and GC times.
   */
  public long getCycleCount() {
    double seconds = getNanoseconds() / 1000000000.0;
    return (long) (seconds * cpuSpeedExtractor.getCyclesPerSecond());
  }

  /**
   * Returns the number of CPU-nanoseconds used by the current
   * request, plus a fraction of any background work (e.g.  hotspot,
   * GC) done by the JVM while this request was executing.
   */
  @Override
  public long getNanoseconds() {
    long total = cpuUsageTimer.getNanoseconds();
    for (Timer timer : extraTimers) {
      total += timer.getNanoseconds();
    }
    return total;
  }

  @Override
  public String toString() {
    double cpuSeconds = cpuUsageTimer.getNanoseconds() / 1000000000.0;
    double wallclockSeconds = wallclockTimer.getNanoseconds() / 1000000000.0;
    StringBuilder builder =
        new StringBuilder(
            String.format(
                "%.3f CPU / %.3f wallclock (%.1f%%), %.3f Mcycles@%.1fGHz",
                cpuSeconds,
                wallclockSeconds,
                100.0 * getCpuRatio(),
                getCycleCount() / 1000000.0,
                cpuSpeedExtractor.getCyclesPerSecond() / 1000000000.0));
    if (extraTimers.length > 0) {
      builder.append(Arrays.toString(extraTimers));
    }
    return builder.toString();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy