001: package org.cougaar.core.qos.profile;
002:
003: import java.lang.reflect.*;
004: import java.io.*;
005: import java.text.*;
006: import java.util.*;
007: import java.util.regex.*;
008: import org.cougaar.core.agent.*;
009: import org.cougaar.core.component.*;
010: import org.cougaar.core.mts.*;
011: import org.cougaar.core.node.*;
012: import org.cougaar.core.qos.metrics.*;
013: import org.cougaar.core.service.*;
014: import org.cougaar.core.service.wp.*;
015: import org.cougaar.core.thread.*;
016: import org.cougaar.core.wp.resolver.*;
017: import org.cougaar.util.*;
018:
019: /**
020: * This component coordinates the profiler components to
021: * log at the same time.
022: * <p>
023: * An optional "period=<i>LONG</i>" argument is supported,
024: * which defaults to 60000 (one minute).
025: * <p>
026: * If the system property<br>
027: * -Dorg.cougaar.core.society.startTime=<i>LONG</i><br>
028: * is set, this class will use that timestamp as the base
029: * offset for the profiler logs. This is used to align the
030: * number of logged profiling rows across multiple machines
031: * (e.g. if host B starts 2 minutes after host A, the alignment
032: * will add 2 blank rows for each profiler output).
033: */
034: public final class ProfilerCoordinator extends GenericStateModelAdapter
035: implements Component, Runnable {
036:
037: private boolean header = true;
038: private boolean align = true;
039: private long period = 60 * 1000;
040:
041: private ServiceBroker sb;
042: private ThreadService threadService;
043: private Schedulable thread;
044:
045: private ProfilerSP psp;
046:
047: private RarelyModifiedList profilers = new RarelyModifiedList();
048:
049: private long startTime;
050: private int runCount;
051:
052: public void setParameter(Object o) {
053: Arguments args = new Arguments(o);
054: period = args.getLong("period", period);
055: }
056:
057: public void setServiceBroker(ServiceBroker sb) {
058: this .sb = sb;
059: }
060:
061: public void load() {
062: super .load();
063:
064: // advertise our profiler coordination service
065: psp = new ProfilerSP();
066: sb.addService(ProfilerService.class, psp);
067: }
068:
069: public void start() {
070: super .start();
071:
072: // must wait for "start()" to make sure the ThreadService
073: // is loaded, since we're loaded at HIGH priority.
074:
075: // "run()" later
076: scheduleNextRun();
077: }
078:
079: public void run() {
080: // invoke profilers
081: List l = profilers.getUnmodifiableList();
082: for (int i = 0, ln = l.size(); i < ln; i++) {
083: ProfilerService.Client c = (ProfilerService.Client) l
084: .get(i);
085: c.run();
086: }
087:
088: // run again later
089: scheduleNextRun();
090: }
091:
092: private void scheduleNextRun() {
093: if (startTime > 0) {
094: // already initialized, schedule next run.
095: //
096: // adjust to fixed interval
097: runCount++;
098: long nextTime = startTime + runCount * period;
099: long now = System.currentTimeMillis();
100: long delta = (nextTime - now);
101: if (delta <= 0) {
102: thread.start();
103: } else {
104: thread.schedule(delta);
105: }
106: return;
107: }
108:
109: // get thread
110: ThreadService threadService = (ThreadService) sb.getService(
111: this , ThreadService.class, null);
112: thread = threadService.getThread(this , this ,
113: "ProfilerCoordinator");
114: sb.releaseService(this , ThreadService.class, threadService);
115:
116: // get ACME time when first node was launched
117: long t = -1;
118: String value = System
119: .getProperty("org.cougaar.core.society.startTime");
120: if (value != null) {
121: try {
122: DateFormat f = new SimpleDateFormat("MM/dd/yyy H:mm:ss");
123: f.setTimeZone(TimeZone.getTimeZone("GMT"));
124: t = f.parse(value).getTime();
125: } catch (ParseException e) {
126: }
127: }
128: long now = System.currentTimeMillis();
129: if (t <= 0 || t > now) {
130: // no ACME timestamp, not aligned
131: t = now;
132: }
133: startTime = t;
134:
135: if (startTime == now) {
136: thread.start();
137: return;
138: }
139: // align w/ society time
140: runCount = (int) ((now - startTime) / period);
141: long rem = (now - startTime) % period;
142: if (rem > 0) {
143: runCount++;
144: }
145: long delta = (rem > 0 && rem < period ? (period - rem) : 0);
146: if (delta <= 0) {
147: thread.start();
148: } else {
149: thread.schedule(delta);
150: }
151: }
152:
153: private final class ProfilerSP extends ServiceProviderBase {
154: protected Class getServiceClass() {
155: return ProfilerService.class;
156: }
157:
158: protected Class getClientClass() {
159: return ProfilerService.Client.class;
160: }
161:
162: protected void register(Object client) {
163: profilers.add(client);
164: }
165:
166: protected void unregister(Object client) {
167: profilers.remove(client);
168: }
169:
170: protected Service getService(Object client) {
171: return new SI(client);
172: }
173:
174: protected class SI extends MyServiceImpl implements
175: ProfilerService {
176: public SI(Object client) {
177: super (client);
178: }
179:
180: public boolean logHeader() {
181: return header;
182: }
183:
184: public boolean logAlign() {
185: return align;
186: }
187:
188: public int getRunCount() {
189: return runCount;
190: }
191: }
192: }
193: }
|