/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com) 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 gcinc; import java.util.Vector; import util.Dbg; import com.jopdesign.sys.Const; import com.jopdesign.sys.GC; import com.jopdesign.sys.Native; import joprt.RtThread; public class Latency { final static String TASK_SET = "hpclg"; final static int TEST_TIME = 60; final static int ARRAY_SIZE = 4096/4; final static boolean USE_ARRAY = true; static class HFThread extends RtThread { public HFThread(int prio, int us) { super(prio, us); period = us; } int period; int expected; int max, min; int cnt; boolean notFirst; public void run() { for (;;) { waitForNextPeriod(); int t = Native.rdMem(Const.IO_US_CNT); if (!notFirst) { expected = t+period; notFirst = true; } else { int diff = t-expected; if (diff>max) max = diff; if (diff<min) min = diff; // if (++cnt==1000000) { // result(); // } expected += period; } work(); } } void work() { // nothing for the HF thread } void result() { Dbg.wr("max=", max); Dbg.wr("max=", min); for (;;); } } // static Vector v; static SimpleList sl; static class MFThread extends HFThread { int nr; public MFThread(int prio, int us) { super(prio, us); } void work() { if (USE_ARRAY) { sl.append(new int[ARRAY_SIZE]); } else { sl.append(new Integer(nr)); } // synchronized (v) { // v.addElement(new Integer(nr)); // } ++nr; } } static class PooledMFThread extends HFThread { int nr; int [][] pool; int poolIndex; public PooledMFThread(int prio, int us) { super(prio, us); pool = new int[sl.POOL_SIZE][ARRAY_SIZE]; poolIndex = 0; } void work() { if (USE_ARRAY) { sl.appendPooled(pool[poolIndex]); poolIndex++; if (poolIndex >= sl.POOL_SIZE) { poolIndex = 0; } } else { sl.append(new Integer(nr)); } // synchronized (v) { // v.addElement(new Integer(nr)); // } ++nr; } } static class LFThread extends HFThread { int expNr; public LFThread(int prio, int us) { super(prio, us); } void work() { Object o; while ((o = sl.remove())!=null) { if (!USE_ARRAY) { if (((Integer) o).intValue()!=expNr) { System.out.println("List problem"); } } else { // int[] ia = (int []) o; // if (ia[0]!=expNr) { // System.out.println("List problem"); // } } ++expNr; } // int size; // synchronized (v) { // size = v.size(); // } // while (size!=0) { // Object o; // synchronized (v) { // o = v.remove(0); // } // if (((Integer) o).intValue()!=expNr) { // System.out.println("Vector problem"); // } // ++expNr; // synchronized (v) { // size = v.size(); // } // } } } static class GCThread extends RtThread { public GCThread() { super(1, PERIOD_GC); GC.setConcurrent(); } public void run() { for (;;) { Dbg.wr('G'); GC.gc(); waitForNextPeriod(); } } } static class StackThread extends HFThread { public StackThread(int prio, int us) { super(prio, us); } void work() { for (;;) { factorial(5); } } int factorial(int n) { if (n > 1) { return factorial(n-1)*n; } else { waitForNextPeriod(); return 1; } } } /** * Use Dbg instead * @author martin * */ static class LogThread extends RtThread { public LogThread(int prio, int us) { super(prio, us); } public void run() { int cnt = 0; int subCnt = 0; for (;;) { waitForNextPeriod(); // emulate a period of 1 second if (++subCnt >= (1000*1000)/PERIOD_LOG) { subCnt = 0; if (hft!=null) { Dbg.wr("hft max=", hft.max); Dbg.wr("hft min=", hft.min); } if (++cnt >= TEST_TIME) { synchronized(System.out) { System.out.println("JVM exit!"); } } } } } } static HFThread hft; // Changes in the scheduler to get low latency values: // TIM_OFF to 2 // omit time adjustments on a missed deadline in // waitForNextPeriod() // Results for 100 MHz: // 107 is without jitter when running it alone // TODO verify the following results: // with output thread 10 us // with prod/cons threads (no GC) 16 us // with GC 72 us (77 us) public static final int PERIOD_HIGH = 107; // 211; public static final int PERIOD_MEDIUM = 2003; // 1009; public static final int PERIOD_LOW = 10007; // 10853; public static final int PERIOD_STACK = 15013; public static final int PERIOD_LOG = 25000; public static final int PERIOD_GC = 50021; // 200183; // for slower JOP versions (<100MHz) // public static final int PERIOD_HIGH = 200; // public static final int PERIOD_MEDIUM = 2000; // public static final int PERIOD_LOW = 20000; // public static final int PERIOD_GC = 400000; /** * @param args */ public static void main(String[] args) { Dbg.initSerWait(); // v = new Vector(20); sl = new SimpleList(); if (TASK_SET.indexOf('h') >= 0) { hft = new HFThread(6, PERIOD_HIGH); } if (TASK_SET.indexOf('p') >= 0) { new MFThread(5, PERIOD_MEDIUM); } else if (TASK_SET.indexOf('q') >= 0) { new PooledMFThread(5, PERIOD_MEDIUM); } if (TASK_SET.indexOf('c') >= 0) { new LFThread(4, PERIOD_LOW); } if (TASK_SET.indexOf('s') >= 0) { new StackThread(3, PERIOD_STACK); } if (TASK_SET.indexOf('l') >= 0) { new LogThread (2, PERIOD_LOG); } if (TASK_SET.indexOf('g') >= 0) { new GCThread(); } RtThread.startMission(); // that one is mandatory to get low latency! // check RtThreadImpl why. for(;;); } }