/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) Martin Schoeberl <martin@jopdesign.com> Thomas B. Preusser <thomas.preusser@tu-dresden.de> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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, see <http://www.gnu.org/licenses/>. */ package csp.stream; import csp.PrivateScope; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.engines.AESLightEngine; import java.util.Random; import joprt.RtThread; /** * Streaming benchmark with four processing stages: * * 1. Data Generation 2. Encryption 3. Decryption 4. Verification * * This benchmark can, by its nature, not scale beyond 4 independent Threads. * The measured performance will typically scale even less due to * platform-dependent imbalances of the computational complexities of the * individual stages. Moreso, the serialized version running within a single * Thread may even perform best on platforms with significant cache memory due * to the improved locality. Thus, this benchmark also evaluates the performance * of the inter-Thread communication. * * @author Thomas B. Preusser <thomas.preusser@tu-dresden.de> * @author Martin Schoeberl <martin@jopdesign.com> */ public class AESSPM { final static int BLOCK_SIZE = 128; // This MUST be a multiple of 16. final static int POOL_LENGTH = 8; final BufferQueue q1, q2, q3, free; final Source source; final Encrypt enc; final Decrypt dec; final Sink sink; final Runnable[] runners; private int blockCnt; static volatile boolean finished; public AESSPM() { // Pool of Data Blocks q1 = new BufferQueue(POOL_LENGTH); q2 = new BufferQueue(POOL_LENGTH); q3 = new BufferQueue(POOL_LENGTH); free = new BufferQueue(POOL_LENGTH); for (int i = 0; i < POOL_LENGTH; ++i) { final byte[] block = new byte[BLOCK_SIZE]; free.checkedEnq(block); } final CipherParameters params; { // Encryption Parameters final byte[] key = new byte[16]; final Random rnd = new Random(127); for (int i = key.length; i > 0; key[--i] = (byte) rnd.nextInt()) ; params = new KeyParameter(key); } source = new Source(); enc = new Encrypt(params); dec = new Decrypt(params); sink = new Sink(); runners = new Runnable[] { source, enc, dec, sink }; } public String toString() { return "AESSPM"; } protected Runnable[] getWorkers() { return runners; } protected int getDepth() { return 4; } protected void reset(int cnt) { finished = false; blockCnt = cnt; } protected boolean isFinished() { return finished; } private class Source implements Runnable { public void run() { PrivateScope scope = new PrivateScope(1000); Runnable r = new Runnable() { public void run() { Random rnd = new Random(); rnd.setSeed(127); int cnt = 0; while (cnt < blockCnt) { if (!free.empty() && !q1.full()) { final byte[] block = free.deq(); for (int i = 0; i < block.length; i++) { block[i] = (byte) rnd.nextInt(); } q1.enq(block); ++cnt; } } } }; scope.enter(r); } } private class Encrypt implements Runnable { byte[] ciph = new byte[BLOCK_SIZE]; public Encrypt(CipherParameters params) { } public void run() { PrivateScope scope = new PrivateScope(1000); Runnable r = new Runnable() { public void run() { int cnt = 0; final byte[] key = new byte[16]; final Random rnd = new Random(127); for (int i = key.length; i > 0; key[--i] = (byte) rnd.nextInt()) ; CipherParameters p = new KeyParameter(key); final BlockCipher crypt; crypt = new AESLightEngine(); crypt.init(true, p); while (cnt < blockCnt) { if (!q1.empty() && !q2.full()) { final byte[] block = q1.deq(); int ofs = BLOCK_SIZE; do { ofs -= crypt.getBlockSize(); crypt.processBlock(block, ofs, ciph, ofs); } while (ofs > 0); q2.enq(ciph); ciph = block; ++cnt; } } } }; scope.enter(r); } } private class Decrypt implements Runnable { byte[] deciph = new byte[BLOCK_SIZE]; public Decrypt(CipherParameters params) { } public void run() { PrivateScope scope = new PrivateScope(1000); Runnable r = new Runnable() { public void run() { int cnt = 0; final byte[] key = new byte[16]; final Random rnd = new Random(127); for (int i = key.length; i > 0; key[--i] = (byte) rnd.nextInt()) ; CipherParameters p = new KeyParameter(key); final BlockCipher decrypt; decrypt = new AESLightEngine(); decrypt.init(false, p); while (cnt < blockCnt) { if (!q2.empty() && !q3.full()) { final byte[] block = q2.deq(); int ofs = BLOCK_SIZE; do { ofs -= decrypt.getBlockSize(); decrypt.processBlock(block, ofs, deciph, ofs); } while (ofs > 0); q3.enq(deciph); deciph = block; ++cnt; } } } }; scope.enter(r); } } private class Sink implements Runnable { boolean ok = true; public void run() { PrivateScope scope = new PrivateScope(1000); Runnable r = new Runnable() { public void run() { Random rnd = new Random(); rnd.setSeed(127); int cnt = 0; while (cnt < blockCnt) { if (!q3.empty() && !free.full()) { final byte[] block = q3.deq(); for (int i = 0; i < block.length; i++) { if (block[i] != (byte) rnd.nextInt()) ok = false; } free.enq(block); ++cnt; } } } }; scope.enter(r); finished = true; } } public static void main(String[] args) { AESSPM aes = new AESSPM(); // Initialization for benchmarking int start = 0; int stop = 0; int time = 0; System.out.println("AES Benchmark with SPM"); int nrCpu = Runtime.getRuntime().availableProcessors(); if (nrCpu < 5) { throw new Error("Not enogh CPUs"); } // ni must be translated from proc index to NoC address! new RtThread(aes.source, 1, 1000).setProcessor(1); new RtThread(aes.enc, 1, 1000).setProcessor(2); new RtThread(aes.dec, 1, 1000).setProcessor(3); new RtThread(aes.sink, 1, 1000).setProcessor(4); aes.reset(1000); // start the other CPUs System.out.println("starting cpus."); RtThread.startMission(); start = (int) System.currentTimeMillis(); while (!finished) { ; } // End of measurement stop = (int) System.currentTimeMillis(); System.out.println("StartTime: " + start); System.out.println("StopTime: " + stop); time = stop - start; System.out.println("TimeSpent: " + time); System.out.println("Result = "+aes.sink.ok); } }