gt: 			for (int j=0; j < keyPairs.length; ++j) {
context: /*
   * A CCNx library test.
   *
   * Copyright (C) 2010-2012 Palo Alto Research Center, Inc.
   *
   * This work is free software; you can redistribute it and/or modify it under
   * the terms of the GNU General Public License version 2 as published by the
   * Free Software Foundation. 
   * This work is distributed in the hope that it will be useful, but WITHOUT ANY
   * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
   * for more details. You should have received a copy of the GNU General Public
   * License along with this program; if not, write to the
   * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   * Boston, MA 02110-1301, USA.
   */
  
  package org.ccnx.ccn.test;
  
  import java.security.DigestOutputStream;
  import java.security.KeyPair;
  import java.security.KeyPairGenerator;
  import java.security.MessageDigest;
  import java.security.PrivateKey;
  import java.security.PublicKey;
  import java.text.DecimalFormat;
  import java.text.NumberFormat;
  import java.util.Random;
  
  import org.ccnx.ccn.CCNHandle;
  import org.ccnx.ccn.config.UserConfiguration;
  import org.ccnx.ccn.impl.CCNNetworkManager;
  import org.ccnx.ccn.impl.CCNFlowControl.SaveType;
  import org.ccnx.ccn.impl.security.crypto.CCNDigestHelper;
  import org.ccnx.ccn.impl.security.crypto.util.SignatureHelper;
  import org.ccnx.ccn.impl.support.Tuple;
  import org.ccnx.ccn.io.NoMatchingContentFoundException;
  import org.ccnx.ccn.io.NullOutputStream;
  import org.ccnx.ccn.io.content.CCNStringObject;
  import org.ccnx.ccn.profiles.SegmentationProfile;
  import org.ccnx.ccn.profiles.VersioningProfile;
  import org.ccnx.ccn.protocol.ContentName;
  import org.ccnx.ccn.protocol.ContentObject;
  import org.ccnx.ccn.protocol.Interest;
  import org.ccnx.ccn.protocol.Signature;
  import org.junit.BeforeClass;
  import org.junit.Test;
  
  
  /**
   * This is not a unit test designed to verify functionality.
   * Instead, this test times some operations for basic benchmarking.
   * @author jthornto
   *
   */
  public class BenchmarkTest {
  
  	public static final int NUM_ITER = 1000;
  	public static final int NUM_KEYGEN = 100; // Key generation is really slow
  	
  	public static final double NanoToMilli = 1000000.0d;
  	public static final double NanoToSec = 1000000000000.0d;
  	
  	public static CCNTestHelper testHelper = new CCNTestHelper(BenchmarkTest.class);
  	public static CCNHandle handle;
  
  	public static ContentName testName;
  	public static byte[] shortPayload;
  	public static byte[] longPayload;
  	public static byte[] veryLongPayload;
  	public static byte [][] payloads;
  	
  	// Need to benchmark multiple key lengths
  	public static final int [] keyLengths = new int[]{512, 1024, 2048};
  	
  	// Need to benchmark multiple digest algorithms. MD5 not used for signing,
  	// but is used for non-security critical applications.
  	public static final String [] digestAlgorithms = new String[]{"MD5", "SHA1", CCNDigestHelper.DEFAULT_DIGEST_ALGORITHM};
  
  	public static final int LONG_LENGTH = 1000;
  	public static final int VERY_LONG_LENGTH = 4096; // our actual packet length
  	
  	public static ContentObject [] contentObjects;
  	public static ContentObject [] unsignedContentObjects;
  	
  	// Default algorithm, add ECC later
  	public static KeyPair[] keyPairs = new KeyPair[keyLengths.length];
  	
  	public static NumberFormat format = DecimalFormat.getNumberInstance();
  	
  	static abstract class Operation<T extends Object,U extends Object> {
  		abstract Object execute(T input, U parameter) throws Exception;
  		
  		int size(T input) {
  			if (null == input) {
  				return -1;
  			} else if (input instanceof byte[]) {
  				return ((byte[])input).length;
  			} else if (input instanceof ContentObject) {
  				return ((ContentObject)input).content().length;
  			} else {
  				throw new RuntimeException("Unsupported input type " + input.getClass());
  			}
  		}
  
  		public void runBenchmark(String desc, T input, U parameter) throws Exception {
  			runBenchmark(NUM_ITER, desc, input, parameter);
  		}
  
  		public void runBenchmark(int count, String desc, T input, U parameter) throws Exception {
  			long start = System.nanoTime();
  			execute(input, parameter);
  			long dur = System.nanoTime() - start;
  			//System.out.println("Start " + start + " dur " + dur);
  			int size = size(input);
  			System.out.println("Initial time to " + desc + (size >= 0 ? " (payload " + size(input) + " bytes)" : "") +
  					" = " + dur/NanoToMilli + " ms.");
  			
  			start = System.nanoTime();
  			for (int i=0; i<count; i++) {
  				execute(input, parameter);
  			}
  			dur = System.nanoTime() - start;
  			System.out.println("Avg. to " + desc + " (" + count + " iterations) = " + 
  					dur/count/NanoToMilli + " ms. (" + 
  					format.format(NanoToSec/dur) + " operations/sec)");		
  		}
  	}
  	
  	@BeforeClass
  	public static void setUpBeforeClass() throws Exception {
  		ContentName namespace = testHelper.getTestNamespace("benchmarkTest");
  		testName = new ContentName(namespace, "BenchmarkObject");
  		testName = VersioningProfile.addVersion(testName);
  		shortPayload = ("this is sample segment content").getBytes();
  		longPayload = new byte[LONG_LENGTH];
  		Random rnd = new Random();
  		rnd.nextBytes(longPayload);
  		veryLongPayload = new byte[VERY_LONG_LENGTH];
  		rnd.nextBytes(veryLongPayload);
  		payloads = new byte [][]{shortPayload, longPayload, veryLongPayload};
  		
  		contentObjects = new ContentObject[payloads.length];
  		unsignedContentObjects = new ContentObject[payloads.length];
  		// Should have content objects signed by multiple key types...
  		ContentName segmentName = SegmentationProfile.segmentName(testName, 0);
  		for (int i=0; i < payloads.length; ++i) {
  			contentObjects[i] = ContentObject.buildContentObject(segmentName, payloads[i], null, null, SegmentationProfile.getSegmentNumberNameComponent(0));
  			unsignedContentObjects[i] = new ContentObject(contentObjects[i].name(), contentObjects[i].signedInfo(), contentObjects[i].content(), (Signature) null);
  		}
  		
  		final KeyPairGenerator kpg = KeyPairGenerator.getInstance(UserConfiguration.defaultKeyAlgorithm());
  		for (int i=0; i < keyLengths.length; ++i) {
  			kpg.initialize(keyLengths[i]);
  			keyPairs[i] = kpg.generateKeyPair();
  		}
  		format.setMaximumFractionDigits(3);
  		
  		handle = CCNHandle.open();
  		System.out.println("Benchmark Test starting on " + System.getProperty("os.name"));
  	}
  
  	@Test
  	public void testDigest() throws Exception {
  		System.out.println("==== Digests");
  		Operation<byte[],String> digest = new Operation<byte[],String>() {
  			Object execute(byte[] input, String algorithm) throws Exception {
  				MessageDigest md = MessageDigest.getInstance(algorithm);
  				md.update(input);
  				return md.digest();
  			}
  		};
  		for (int i=0; i < digestAlgorithms.length; ++i) {
  			System.out.println("--- Raw = digest only of byte[] using " + digestAlgorithms[i]);
  			for (int j=0; j<payloads.length; ++j) {
  				digest.runBenchmark("raw digest (" + payloads[j].length + " bytes)", 
  						payloads[j], digestAlgorithms[i]);
  			}
  			System.out.println("");
  		}
  
  		
  		Operation<ContentObject, String> digestObj = new Operation<ContentObject, String>() {
  			Object execute(ContentObject input, String algorithm) throws Exception {
  				MessageDigest md = MessageDigest.getInstance(algorithm);
  				DigestOutputStream dos = new DigestOutputStream(new NullOutputStream(), md);
  				input.encode(dos);
  				return md.digest();
  			}
  		};
  
  		for (int i=0; i < digestAlgorithms.length; ++i) {
  			System.out.println("--- Raw = digest of contentObject using " + digestAlgorithms[i]);
  			for (int j=0; j<contentObjects.length; ++j) {
  				digestObj.runBenchmark("ContentObject digest (content " + contentObjects[j].contentLength() + " bytes) ", 
  						contentObjects[j], digestAlgorithms[i]);
  			}
  			System.out.println("");
  		}
  	}
  		
  	@Test
  	public void testEncode() throws Exception {
  		System.out.println("==== Encoding");
  		
  		Operation<ContentObject, String> encodeObj = new Operation<ContentObject, String>() {
  			Object execute(ContentObject input, String codec) throws Exception {
  				return input.encode(codec);
  			}
  		};
  
  		for (int j=0; j<contentObjects.length; ++j) {
  			encodeObj.runBenchmark("ContentObject encode (content " + contentObjects[j].contentLength() + " bytes) ", 
  					contentObjects[j], null);
  		}
  		System.out.println("");
  
  		Operation<ContentObject, Object> prepareObj = new Operation<ContentObject, Object>() {
  			Object execute(ContentObject input, Object ignored) throws Exception {
  				return ContentObject.prepareContent(input.name(), input.signedInfo(), input.content());
  			}
  		};
  
  		System.out.println("Prepare content: perform the encoding steps necessary for signing:");
  		for (int j=0; j<contentObjects.length; ++j) {
  			prepareObj.runBenchmark("ContentObject prepareDigest (content " + contentObjects[j].contentLength() + " bytes) ", 
  					contentObjects[j], null);
  		}
  		System.out.println("");
  
  	}
  
  	@Test
  	public void testRawSigning() throws Exception {
  		
  		// We need to be able to benchmark signing using multiple algorithms;
  		// probably should make this depend on digest algorithm as well. 
  		// For right now, just parameterize on key size.
  		// Add ECC once we can test for its presence
  		Operation<byte[], Tuple<String,PrivateKey>> sign = new Operation<byte[], Tuple<String,PrivateKey>>() {
  
  			Object execute(byte[] input, Tuple<String,PrivateKey> signingParams) throws Exception {
  				return SignatureHelper.sign(signingParams.first(), input, signingParams.second());
  			}
  		};
  		
  		// Need to handle multiple length of key, and at least SHA1 and SHA256
  		for (int i = 1; i < digestAlgorithms.length; ++i) {
  			// skip MD-5
  			System.out.println("==== PK Signing: Digest: " + digestAlgorithms[i]);
  			for (int j=0; j < keyPairs.length; ++j) {
  				System.out.println("======= " + keyLengths[j] + "-bit " + keyPairs[j].getPublic().getAlgorithm() + " Key with " + digestAlgorithms[i] + ":");
  				for (int k=0; k < payloads.length; ++k) {
  					sign.runBenchmark("sign " + payloads[k].length + " bytes ",
  							payloads[k], new Tuple<String,PrivateKey>(digestAlgorithms[i],keyPairs[j].getPrivate()));
  				}
  				System.out.println("");
  			}
  		}
  		System.out.println("");
  		
  		Operation<Tuple<byte[],byte[]>, Tuple<String,PublicKey>> verify = 
  			new Operation<Tuple<byte[],byte[]>, Tuple<String,PublicKey>>() {
  			
  			Object execute(Tuple<byte[],byte[]> input, Tuple<String,PublicKey> verifyParams) throws Exception {
  				return SignatureHelper.verify(input.first(), input.second(), 
  						verifyParams.first(), verifyParams.second());
  			}
  			
  			int size(Tuple<byte[], byte[]> input) {
  				return input.first().length;
  			}
  		};
  
  		for (int i = 1; i < digestAlgorithms.length; ++i) {
  			// skip MD-5
  			System.out.println("==== PK Verifying: Digest: " + digestAlgorithms[i]);
  