001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.node;
028:
029: import org.cougaar.bootstrap.SystemProperties;
030: import org.cougaar.core.component.ServiceBroker;
031: import org.cougaar.core.service.ThreadService;
032: import org.cougaar.core.thread.Schedulable;
033: import org.cougaar.util.log.Logging;
034:
035: /**
036: * A low-priority "heartbeat" function that prints a period
037: * every few seconds when nothing else is happening.
038: *
039: * @property org.cougaar.core.agent.heartbeat
040: * Unless disabled, the node will provide a heartbeat to the vm.
041: *
042: * @property org.cougaar.core.agent.idleInterval
043: * How long between idle detection and heartbeat cycles (prints '.');
044: *
045: * @property org.cougaar.core.agent.idle.verbose
046: * If <em>true</em>, will print elapsed time (seconds) since
047: * the agent's start every idle.interval millis.
048: *
049: * @property org.cougaar.core.agent.idle.verbose.interval=60000
050: * The number of milliseconds between verbose idle reports.
051: *
052: * @property org.cougaar.core.agent
053: * quiet Makes standard output as quiet as possible.
054: * If Heartbeat is running, will not print dots.
055: */
056: public final class Heartbeat {
057:
058: private static int idleInterval = 5 * 1000;
059: private static boolean idleVerbose = false; // don't be verbose
060: private static long idleVerboseInterval = 60 * 1000L; // 1 minute
061: private static long maxIdleInterval;
062:
063: static {
064: idleInterval = SystemProperties.getInt(
065: "org.cougaar.core.agent.idleInterval", idleInterval);
066: maxIdleInterval = (idleInterval + (idleInterval / 10));
067: idleVerbose = SystemProperties.getBoolean(
068: "org.cougaar.core.agent.idle.verbose", idleVerbose);
069: idleVerboseInterval = SystemProperties.getInt(
070: "org.cougaar.core.agent.idle.verbose.interval",
071: (int) idleVerboseInterval);
072: }
073:
074: private long firstTime;
075: private long lastVerboseTime;
076:
077: private static long lastHeartbeat = 0L;
078: private static long idleTime = 0L;
079:
080: private Schedulable schedulable;
081:
082: /** Only node can construct a Heartbeat */
083: Heartbeat() {
084: firstTime = System.currentTimeMillis();
085: lastVerboseTime = firstTime;
086: }
087:
088: synchronized void start(ServiceBroker sb) {
089: if (schedulable != null)
090: throw new RuntimeException(
091: "Attempted to restart Heartbeat!");
092:
093: ThreadService tsvc = (ThreadService) sb.getService(this ,
094: ThreadService.class, null);
095: //Want this thread to be lowest priority, i.e. run only after
096: // every thing else has run. With the thread lanes, the best we can do
097: // is run in the default pool.
098: schedulable = tsvc.getThread(this , new Beater(), "Heartbeat");
099: schedulable.schedule(idleInterval);
100: sb.releaseService(this , ThreadService.class, tsvc);
101: }
102:
103: synchronized void stop() throws SecurityException {
104: if (schedulable == null)
105: throw new RuntimeException(
106: "Attempted to stop a stopped Heartbeat!");
107: schedulable.cancel();
108: }
109:
110: private class Beater implements Runnable {
111: public void run() {
112: // initialize the values
113: firstTime = System.currentTimeMillis();
114: lastVerboseTime = firstTime;
115:
116: showProgress(".");
117: // if heartbeat actually gets to run at least every 5.5 seconds,
118: // we'll consider the VM idle.
119:
120: //TBD: The logic of this test assumes that this schedulable will
121: // be run only after all other work has completed. This is not
122: // the case with a thread service thread which does not have low
123: // priority. A better test would be to query the thread control
124: // service for the "load average" There seems to be no client
125: // for idle time, so we will leave the old logic in place as
126: // documenation for when this functionality will be revisited
127: long t = System.currentTimeMillis();
128: if (lastHeartbeat != 0) {
129: long delta = t - lastHeartbeat;
130: if (delta <= maxIdleInterval) {
131: // we're pretty much idle
132: idleTime += delta;
133: } else {
134: idleTime = 0;
135: }
136: }
137: lastHeartbeat = t;
138:
139: if (idleVerbose) {
140: long delta = t - lastVerboseTime;
141: if (delta >= idleVerboseInterval) {
142: showProgress("("
143: + Long
144: .toString(((t - firstTime) + 500) / 1000)
145: + ")");
146: lastVerboseTime = t;
147: }
148: }
149: schedulable.schedule(idleInterval);
150: }
151: }
152:
153: private static void showProgress(String p) {
154: Logging.printDot(p);
155: }
156:
157: /**
158: * @return an estimate of how long in milliseconds the VM has been
159: * approximately idle.
160: */
161: public long getIdleTime() {
162: long delta = System.currentTimeMillis() - lastHeartbeat;
163: if (delta <= maxIdleInterval) {
164: return idleTime + delta;
165: } else {
166: return 0;
167: }
168: }
169:
170: }
|