Project: Flume-Hive
/**
 * Licensed to Cloudera, Inc. under one 
 * or more contributor license agreements.  See the NOTICE file 
 * distributed with this work for additional information 
 * regarding copyright ownership.  Cloudera, Inc. licenses this file 
 * to you 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 
 * 
 *     http://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.cloudera.util; 
 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.net.InetAddress; 
import java.net.UnknownHostException; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Vector; 
 
import com.google.common.base.Preconditions; 
 
/**
 * Simple class to consolidate benchmarking and timing code. This will help me 
 * find the bottlenecks. 
 *  
 * Usage: create new benchmark. call mark with comments whenever wanted. call 
 * done to flush print writer. 
 *  
 * std out is used for human readable results, stderr is used for csv formatted 
 * data. 
 */
 
public class Benchmark { 
  long start; 
  long last; 
  PrintWriter out; 
  PrintWriter log; 
  List<String> values = new ArrayList<String>(); 
  String name; 
 
  public Benchmark(String name, PrintWriter o, PrintWriter l) { 
    Preconditions.checkNotNull(o); 
    Preconditions.checkNotNull(l); 
 
    this.name = name; 
    out = o; 
    log = l; 
 
    // do this first because of potential dns lookup delay. 
    try { 
      String host = InetAddress.getLocalHost().getHostName(); 
      values.add(host); 
    } catch (UnknownHostException e) { 
      values.add("localhost"); 
      e.printStackTrace(); 
    } 
 
    start = System.nanoTime(); 
    last = start; 
    // do a GC cleanup before each benchmark test. 
    // Runtime rt = Runtime.getRuntime(); 
    // rt.gc(); 
    flushMemory(); 
 
    Runtime r = Runtime.getRuntime(); 
    long fmem = r.freeMemory(); 
    long tmem = r.totalMemory(); 
    long umem = tmem - fmem; // memory used 
    out.printf("[%,18dus, %,18d b mem]\tStarting (after gc) \n"0, umem); 
  } 
 
  // default to standard out. 
  public Benchmark() { 
    this(nullnew PrintWriter(new OutputStreamWriter(System.out)), 
        new PrintWriter(new OutputStreamWriter(System.err))); 
  } 
 
  // this was named, make the values go to std err. 
  public Benchmark(String name) { 
    this(name, new PrintWriter(new OutputStreamWriter(System.out)), 
        new PrintWriter(new OutputStreamWriter(System.err))); 
  } 
 
  public void mark(Object... logs) { 
    StringBuffer b = new StringBuffer(); 
    boolean first = true
    for (Object o : logs) { 
      if (!first) 
        b.append(','); 
      b.append(o.toString()); 
      first = false
      values.add(o.toString()); 
    } 
 
    _mark(b.toString()); 
  } 
 
  void _mark(String s) { 
    // record time before we incur gc 
    long now = System.nanoTime(); 
    long delta = (now - last); 
    long cumulative = (now - start); 
 
    // force a GC to get memory usage estimate 
    flushMemory(); 
 
    Runtime r = Runtime.getRuntime(); 
    long fmem = r.freeMemory(); 
    long tmem = r.totalMemory(); 
    long umem = tmem - fmem; // memory used 
 
    // results 
    out.printf("[%,18dns d %,18dns %,18d b mem]\t%s\n", cumulative, delta, 
        umem, s); 
    // values.add(s); 
    values.add("" + delta); 
    values.add("" + umem); 
 
    // skip over gc time 
    last = System.nanoTime(); // don't count gc time. 
  } 
 
  /**
   * Dumps results in human readable form. 
   */
 
  public void done() { 
    out.flush(); 
    printCsvLog(log); 
  } 
 
  public PrintWriter getOut() { 
    return out; 
  } 
 
  public PrintWriter getLog() { 
    return log; 
  } 
 
  /**
   * In case I want to print the csv report summary 
   *  
   * @param pw 
   */
 
  public void printCsvLog(PrintWriter pw) { 
    Preconditions.checkNotNull(pw); 
    boolean first = true
    if (name != null) { 
      pw.print(name); 
      first = false
    } 
 
    for (String s : values) { 
      if (!first) 
        pw.print(","); 
      pw.print(s); 
      first = false
    } 
    pw.println(); 
    pw.flush(); 
  } 
 
  // Javadoc says Runtime.gc is just a hint! Sun's JDK with default GC actually 
  // triggers a gc. 
  public static void flushMemory() { 
    System.gc(); 
  } 
 
  /**
   * alternate method to force GC. It allocates memory until it gets and 
   * OutOfMemoryError, release the data, and then allocates one more time to 
   * guarantee a forced GC. 
   *  
   * With sun's JDK on default setting System.gc() is apparently sufficient. 
   */
 
  public static void flushMemoryExhaust() { 
 
    // Use a vector to hold the memory. 
    Vector<byte[]> v = new Vector<byte[]>(); 
    int count = 0
    // increment in megabyte chunks initially 
    int size = 1048576
    // Keep going until we would be requesting 
    // chunks of 1 byte 
    while (size > 1) { 
      try { 
        for (; true; count++) { 
          // request and hold onto more memory 
          v.addElement(new byte[size]); 
        } 
      } 
      // If we encounter an OutOfMemoryError, keep 
      // trying to get more memory, but asking for 
      // chunks half as big. 
      catch (OutOfMemoryError bounded) { 
        size = size / 2
      } 
    } 
    // Now release everything for GC 
    v = null
    // and ask for a new Vector as a new small object 
    // to make sure garbage collection kicks in before 
    // we exit the method. 
    v = new Vector<byte[]>(); 
  } 
 
}