import java.io.File; import java.util.*; import com.minamp.net.*; /** Samples the handshake thread's stack to see where TLS time goes (run with -Xint). */ public class HandshakeProfile { public static void main(String[] a) throws Exception { CertVerifier.setRootStore(new PlexTest.RootDir(new File(a[0]))); final String url = a[1]; final int rounds = Integer.parseInt(a[2]); final Map buckets = new TreeMap(); final long[] times = new long[rounds]; final Thread[] worker = new Thread[1]; worker[0] = Threads.create(new Runnable() { public void run() { for (int i = 0; i < rounds; i++) { Http.evictAll(); long t0 = System.nanoTime(); try { Http.get(url, null, 60000).readAll(); } catch (Exception e) { System.out.println(e); } times[i] = (System.nanoTime() - t0) / 1000000; } }}, "hs"); worker[0].start(); while (worker[0].isAlive()) { StackTraceElement[] st = worker[0].getStackTrace(); String b = "other"; for (StackTraceElement e : st) { String c = e.getClassName() + "." + e.getMethodName(); if (c.startsWith("com.minamp.net.CertVerifier.signatureValid")) { b = "our chain check: signature math"; break; } if (c.startsWith("com.minamp.net.CertVerifier")) { b = "our chain check: other"; break; } if (c.contains("Ed25519") || c.contains("X25519") || c.contains("rfc7748")) { b = "X25519 key exchange"; break; } if (c.contains("ECDSASigner") || c.contains("DSADigestSigner")) { b = "ECDSA verify (server signature)"; break; } if (c.contains("RSA")) { b = "RSA"; break; } if (c.contains("math.ec")) { b = "EC math (other)"; break; } if (c.contains("asn1")) { b = "ASN.1 parsing"; break; } if (c.contains("ChaCha") || c.contains("Poly1305") || c.contains("AES") || c.contains("GCM")) { b = "symmetric cipher"; break; } if (c.contains("Digest") || c.contains("HMAC") || c.contains("HKDF")) { b = "hashing/HKDF"; break; } if (c.contains("SecureRandom") || c.contains("Random")) { b = "random"; break; } if (c.contains("java.net") || c.contains("SocketInputStream") || c.contains("NioSocket") || c.contains("read0")) { b = "network wait"; break; } } Integer n = buckets.get(b); buckets.put(b, n == null ? 1 : n + 1); Thread.sleep(3); } int total = 0; for (int v : buckets.values()) total += v; System.out.println("handshake ms: " + Arrays.toString(times)); List> l = new ArrayList>(buckets.entrySet()); Collections.sort(l, new Comparator>() { public int compare(Map.Entry x, Map.Entry y) { return y.getValue() - x.getValue(); } }); for (Map.Entry e : l) System.out.printf(" %5.1f%% %s%n", 100.0 * e.getValue() / total, e.getKey()); } }