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.thread;
028:
029: import java.io.PrintWriter;
030: import java.util.Comparator;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.ArrayList;
034:
035: import javax.servlet.http.HttpServletRequest;
036:
037: import org.cougaar.core.component.ServiceBroker;
038: import org.cougaar.core.node.NodeControlService;
039: import org.cougaar.core.service.ThreadControlService;
040: import org.cougaar.core.service.ThreadService;
041: import org.cougaar.core.servlet.ServletFrameset;
042:
043: /**
044: * This servlet displays a more or less current list of {@link
045: * Schedulable}s, both running and queued, at all levels and for all
046: * lanes, in a way that's vaguely remniscent of the unix 'top'
047: * command. It's created by {@link TopPlugin} and uses the {@link
048: * ThreadStatusService} to get its snapshot lists. The access path is
049: * <b>/threads/top</b>.
050: */
051: final class TopServlet extends ServletFrameset {
052:
053: private static final long THRESHOLD = 1000;
054: private ThreadStatusService statusService;
055: private ThreadControlService controlService;
056:
057: private static class Record {
058: Record(String scheduler, Schedulable schedulable, boolean queued) {
059: this .scheduler = scheduler;
060: this .schedulable = schedulable;
061: this .queued = queued;
062: elapsed = System.currentTimeMillis()
063: - schedulable.getTimestamp();
064:
065: }
066:
067: String scheduler;
068: Schedulable schedulable;
069: long elapsed;
070: boolean queued;
071: }
072:
073: // Higher times appear earlier in the list
074: private Comparator<Record> comparator = new Comparator<Record>() {
075: public int compare(Record r, Record s) {
076: if (r.elapsed == s.elapsed) {
077: return 0;
078: } else if (r.elapsed < s.elapsed) {
079: return 1;
080: } else {
081: return -1;
082: }
083: }
084:
085: public boolean equals(Object x) {
086: return x == this ;
087: }
088: };
089:
090: public TopServlet(ServiceBroker sb) {
091: super (sb);
092:
093: NodeControlService ncs = (NodeControlService) sb.getService(
094: this , NodeControlService.class, null);
095:
096: if (ncs == null) {
097: throw new RuntimeException("Unable to obtain service");
098: }
099:
100: ServiceBroker rootsb = ncs.getRootServiceBroker();
101:
102: statusService = (ThreadStatusService) rootsb.getService(this ,
103: ThreadStatusService.class, null);
104: controlService = (ThreadControlService) rootsb.getService(this ,
105: ThreadControlService.class, null);
106:
107: if (statusService == null) {
108: throw new RuntimeException("Unable to obtain service");
109: }
110: }
111:
112: private void printHeaders(PrintWriter out) {
113: out.print("<tr>");
114: out.print("<th align=left><b>State</b></th>");
115: out.print("<th align=left><b>Blocking</b></th>");
116: out.print("<th align=left><b>Time(ms)</b></th>");
117: out.print("<th align=left><b>Level</b></th>");
118: out.print("<th align=left><b>Lane</b></th>");
119: out.print("<th align=left><b>Thread</b></th>");
120: out.print("<th align=left><b>Client</b></th>");
121: out.print("</tr>");
122: }
123:
124: private void printCell(String data, boolean queued, PrintWriter out) {
125: out.print("<td>");
126: if (queued)
127: out.print("<i>");
128: out.print(data);
129: if (queued)
130: out.print("</i>");
131: out.print("</td>");
132: }
133:
134: private void printCell(long data, boolean queued, PrintWriter out) {
135: out.print("<td align=right>");
136: if (queued)
137: out.print("<i>");
138: out.print(data);
139: if (queued)
140: out.print("</i>");
141: out.print("</td>");
142: }
143:
144: private void printRecord(Record record, PrintWriter out) {
145:
146: if (record.elapsed > THRESHOLD) {
147: out.print("<tr bgcolor=\"#ffeeee\">"); // pale-pink background
148: } else {
149: out.print("<tr>");
150: }
151: printCell(record.queued ? "queued" : "running", record.queued,
152: out);
153:
154: String b_string = SchedulableStatus.statusString(
155: record.schedulable.getBlockingType(),
156: record.schedulable.getBlockingExcuse());
157:
158: printCell(b_string, record.queued, out);
159:
160: printCell(record.elapsed, record.queued, out);
161: printCell(record.scheduler, record.queued, out);
162: printCell(record.schedulable.getLane(), record.queued, out);
163: printCell(record.schedulable.getName(), record.queued, out);
164: printCell(record.schedulable.getConsumer().toString(),
165: record.queued, out);
166: out.print("</tr>");
167: }
168:
169: public void printBottomPage(HttpServletRequest request,
170: PrintWriter out) {
171: // lane key
172: out.print("Lane 0: Best Effort");
173: out.print("<br>Lane 1: Will Block");
174: out.print("<br>Lane 2: CPU Intensive");
175: out.print("<br>Lane 3: Well Behaved");
176: }
177:
178: private void printSummary(List status, PrintWriter out) {
179: int running = 0;
180: int queued = 0;
181: int total = status.size();
182: int[] run_counts = new int[ThreadService.LANE_COUNT];
183:
184: Iterator itr = status.iterator();
185: while (itr.hasNext()) {
186: Record record = (Record) itr.next();
187: if (record.queued) {
188: ++queued;
189: } else {
190: ++running;
191: ++run_counts[record.schedulable.getLane()];
192: }
193: }
194:
195: out.print("<br><br><b>");
196: out.print(total);
197: out.print(" thread");
198: if (total != 1)
199: out.print('s');
200: out.print(": ");
201: out.print(queued);
202: out.print(" queued, ");
203: out.print(running);
204: out.print(" running");
205: if (controlService != null) {
206: out.print(", running/max (per lane):");
207: for (int i = 0; i < ThreadService.LANE_COUNT; i++) {
208: out.print(i == 0 ? " " : ", ");
209: out.print(run_counts[i]);
210: out.print("/");
211: out.print(controlService.maxRunningThreadCount(i));
212: }
213: }
214: out.print("</b>");
215: }
216:
217: // Implementations of ServletFrameset's abstract methods
218:
219: public String getPath() {
220: return "/threads/top";
221: }
222:
223: public String getTitle() {
224: return "Threads";
225: }
226:
227: public void printPage(HttpServletRequest request, PrintWriter out) {
228: final List<Record> status = new ArrayList<Record>();
229: ThreadStatusService.Body body = new ThreadStatusService.Body() {
230: public void run(String scheduler, Schedulable schedulable) {
231: Record record = null;
232: int state = schedulable.getState();
233: if (state == CougaarThread.THREAD_PENDING) {
234: record = new Record(scheduler, schedulable, true);
235: } else if (state == CougaarThread.THREAD_RUNNING) {
236: record = new Record(scheduler, schedulable, false);
237: } else {
238: return; // ignore this one
239: }
240:
241: status.add(record);
242: }
243: };
244:
245: statusService.iterateOverStatus(body);
246:
247: printSummary(status, out);
248:
249: if (status.size() == 0) {
250: // Nothing more to print
251: return;
252: }
253:
254: out.print("<hr>");
255: // Sort the records by time
256: java.util.Collections.sort(status, comparator);
257:
258: out.print("<table>");
259: printHeaders(out);
260:
261: for (Record record : status) {
262: printRecord(record, out);
263: }
264:
265: out.print("</table>");
266: }
267:
268: }
|