Mercurial > hg > jslab
view src/samer/tools/RThread.java @ 5:b67a33c44de7
Remove some crap, etc
author | samer |
---|---|
date | Fri, 05 Apr 2019 21:34:25 +0100 |
parents | bf79fb79ee13 |
children |
line wrap: on
line source
/* * Copyright (c) 2000, Samer Abdallah, King's College London. * All rights reserved. * * This software is provided AS iS and WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ package samer.tools; import samer.core.*; import samer.core.util.*; import samer.core.types.*; import java.util.*; /** frame rate regulator */ public class RThread extends Viewable implements Agent, Runnable { Task task, termhook; Thread thread; int prio; boolean running; int numloops=0; int N=10, count; long t0, elapsed, iterations; boolean regulated=true; VDouble target; // target frame rate double actual; // actual frame rate long period, wakeTime,nanos; private volatile boolean paused=false; private volatile boolean kill=false; // .....Constructors................................ public RThread() { this(new NullTask()); } public RThread(Task r) { super("regulator"); Shell.push(node); target = new VDouble("target",50,0); regulated = Shell.getBoolean("regulated",regulated); setPriority(Shell.getDouble("thread.priority",-0.25)); Shell.pop(); setN(actual=target.value); setPeriod(); setAgent(this); task=r; termhook=null; thread=new Thread(this); thread.setPriority(prio); running=false; Shell.registerAgent(this); Shell.registerViewable(this); } public Task onFinish(Task t) { Task old=termhook; termhook=t; return old; } public Viewer getViewer() { return new UI(); } public void dispose() { Shell.deregisterAgent(this); Shell.deregisterViewable(this); target.dispose(); super.dispose(); } public Task getTask() { return task; } public void setTask(Task t) { task=t; } public class Kill extends Exception {} public void interrupt() { thread.interrupt(); } public void join() { try { thread.join(); } catch (InterruptedException ex) {} } public void start() { start(0); } public void start(int n) { paused=false; kill=false; numloops=n; reset(); thread=new Thread(this); thread.setPriority(prio); thread.start(); } /** <b>Important:</b> this method BLOCKS until the * thread co-operatively terminates, either naturally * or by not handling the InterruptedException that * will be thrown by the <code>checkpoint()</code> method * the next time it is called. */ public void kill() { if (!thread.isAlive()) return; synchronized (this) { kill=true; paused=true; thread.interrupt(); // this will interrupt sleep, wait etc } try { thread.join(5000); } catch (Exception ex) { Shell.trace("RThread.kill failed: "+ex); } } public void setPriority(double p) { Shell.trace("thread priority is "+p); if (p==0) { prio=Thread.NORM_PRIORITY; } else if (p>0) { prio=Thread.NORM_PRIORITY+(int)(p*(Thread.MAX_PRIORITY-Thread.NORM_PRIORITY)); } else { prio=Thread.NORM_PRIORITY-(int)(p*(Thread.MIN_PRIORITY-Thread.NORM_PRIORITY)); } } public void pause() { paused=true; } public void unpause() { if (paused) synchronized (this) { paused=false; notifyAll(); } } /** This method blocks if the thread has been paused * and throws an InterruptedException if the thread * has been killed. */ public final void checkpoint() throws Kill { if (paused) synchronized (this) { Shell.trace("pausing"); running=false; task.stopping(); if (kill) throw new Kill(); try { wait(); } catch (Exception ex) {} if (kill) throw new Kill(); running=true; task.starting(); reset(); Shell.trace("unpausing"); } } public void run() { try { Shell.trace("Regulator: init"); task.starting(); running=true; try { if (numloops==0) { for (;;) { task.run(); if (regulated) tick(); //if (regulated) synchronized (this) { wait(); } if (++count>=N) { tock(); changed(); } checkpoint(); } } else { int n=numloops; numloops=0; for (int i=0;i<n;i++) { task.run(); if (regulated) tick(); //if (regulated) synchronized (this) { wait(); } if (++count>=N) { tock(); changed(); } checkpoint(); } task.stopping(); tock(); changed(); } } catch (Kill ex) { throw ex; } catch (Exception ex) { task.stopping(); throw ex; } finally { running=false; Shell.trace("Regulator: term"); if (termhook!=null) { Shell.trace("running termination hook"); try { termhook.run(); } catch (Exception ex) { ex.printStackTrace(); } } } } catch (Kill ex) { System.out.println("Regulator: thread killed"); } catch (Exception ex) { System.out.println("Regulator: "+ex); ex.printStackTrace(); } } private final void tick() throws Exception { long now=System.currentTimeMillis(); if (now<wakeTime) { Thread.sleep(wakeTime-now); wakeTime+=period; } else wakeTime=now+period; } public double fps() { return actual; } public double elapsedTime() { return elapsed/1000.0; } public long iterations() { return iterations; } public void setRate( double r) { target.value=r; target.changed(); } public void regulate() { regulated=true; setPeriod(); } public void deregulate() { regulated=false; } private void setPeriod() { period=(long)(1000.0/target.value); // double T=(1000.0/target.value); // period = (long)T; // nanos = (long)(1000000.0*(T-period)); // Shell.trace("period = "+period+"ms + "+nanos+"ns"); } public void reset() { setPeriod(); count=0; setN(actual); t0=System.currentTimeMillis(); wakeTime=t0+period; } public void tock() { long t = System.currentTimeMillis(); long dt = t-t0; elapsed+=dt; iterations+=count; actual = (1000.0*count)/dt; count = 0; t0 = t; setN(actual); // try to count for 2 seconds setPeriod(); } private void setN(double rate) { // set the number of iterations to time // given a certain rate N=(int)(2*rate); // try to count for 2 seconds if (N==0) N=1; // at least 1! } public void getCommands(Agent.Registry r) { r.add("start").add("pause").add("kill").add("step"); r.add("zero"); // do we want this one here? } public void execute(String c, Environment env) throws Exception { if (c.equals("start") || c.equals("resume")) { if (thread.isAlive()) unpause(); else start(); } else if (c.equals("stop") || c.equals("pause")) pause(); else if (c.equals("step")) { if (!running) { task.starting(); task.run(); task.stopping(); } else { Shell.print("Cannot step while thread is running."); } } else if (c.equals("regulated")) { regulated = X._bool(env.datum(),!regulated); reset(); changed(); } else if (c.equals("zero")) { tock(); elapsed=iterations=0; changed(); } else if (c.equals("tock")) { tock(); changed(); } else if (c.equals("exit") || c.equals("kill")) { Shell.trace("killing thread..."); kill(); Shell.trace("thread killed."); } } class UI extends BaseViewer { NumberViewer actualRate=Shell.createNumberViewer("Actual rate",NumberViewer.TEXT); NumberViewer elapsedTime=Shell.createNumberViewer("Elapsed time",NumberViewer.TEXT); NumberViewer iterationCount=Shell.createNumberViewer("Iterations",NumberViewer.TEXT); Viewer targetViewer; VBoolean reg; UI() { super(RThread.this); setLayout( new StackLayout(2)); panel().setName(getLabel()); targetViewer = target.getViewer(); reg = new VBoolean("regulated",regulated,0); reg.addObserver(this); add( targetViewer.getComponent()); add( actualRate.getComponent()); add( elapsedTime.getComponent()); add( iterationCount.getComponent()); add( reg.getViewer().getComponent()); panel().add(Shell.createButtonsFor(RThread.this)); } public void attach() { targetViewer.attach(); super.attach(); } public void detach() { targetViewer.detach(); super.detach(); } public void update(Observable o, Object src) { if (reg==o && src!=this) { regulated = reg.value; setPeriod(); } if (reg.value!=regulated) { reg.value=regulated; reg.changed(this); } actualRate.set((int)actual); elapsedTime.set((double)(elapsed/1000.0)); iterationCount.set((int)(iterations)); super.update(o,src); } } }