package zeta.handler.statistic;
import java.awt.Color;
import java.awt.Paint;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import zeta.ZetaServlet;
import zeta.util.CachedQueries;
import zeta.util.Charts;
import zeta.util.DatabaseUtils;
import zeta.util.StreamUtils;
import zeta.util.Table;
public class StatisticOverviewHandler extends AbstractHandler {
public StatisticOverviewHandler(ZetaServlet servlet) {
super(servlet, 43200000, 0, 43200000); }
public String createPage(Connection con) throws SQLException, ServletException {
DecimalFormat decimalFormat = new DecimalFormat("#,###");
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.GERMANY);
StringBuffer buffer = new StringBuffer(5*1024);
buffer.append("<ul>\n");
buffer.append(" <li>Participating (");
buffer.append(dateFormat.format(new Date()));
buffer.append("):</li>\n");
buffer.append(" <ul>\n");
buffer.append(" <li>");
Statement stmt = null;
TopProducersHandler handler = (TopProducersHandler)servlet.getStatisticHandler(TopProducersHandler.class);
if (handler != null) {
Table table = handler.getTopProducersTable();
if (table != null) {
int l = table.getRowCount()-2;
Set users = new HashSet(2*l);
for (int i = 0; i < l; ++i) {
String name = ((String)table.getValue(i, 0)).toLowerCase();
int idx = name.lastIndexOf(',');
if (idx > 0) {
name = name.substring(0, idx);
}
users.add(name);
}
buffer.append(decimalFormat.format(new Integer(users.size())));
buffer.append(" users and ");
buffer.append(decimalFormat.format(new Integer(CachedQueries.getNumberOfComputers())));
buffer.append(" computers</li>\n");
} else {
buffer.append("? users and ? computers</li>\n");
}
} else {
buffer.append("? users and ? computers</li>\n");
}
buffer.append(" </ul>\n");
buffer.append(" <li>");
try {
stmt = con.createStatement();
double fpo = 0.0;
ResultSet rs = stmt.executeQuery("SELECT SUM(SQRT((comp.work_unit_id+comp.range)/12.566370614359)*148*1.245*1.246*comp.range),SUM(CAST(range AS DECIMAL(20, 0)))"
+ " FROM zeta.computation comp,zeta.result res"
+ " WHERE res.task_id=comp.task_id"
+ " AND res.work_unit_id=comp.work_unit_id");
if (rs.next()) {
double d = fpo = rs.getDouble(1);
int exp = 0;
while (d > 10.0) {
d /= 10.0;
++exp;
}
int n = (int)Math.floor(d);
buffer.append(n);
buffer.append('.');
buffer.append((int)Math.floor((d-n)*10.0));
buffer.append("<font face=\"Symbol\">×</font>10<sup>");
buffer.append(exp);
buffer.append("</sup> floating-point operations for calculating about ");
d = rs.getDouble(2);
buffer.append((int)(d/1000000000.0));
buffer.append(" billion zeros of the Riemann zeta function in ");
}
rs.close();
int days = 1;
rs = stmt.executeQuery("SELECT DAYS(CURRENT TIMESTAMP)-DAYS(MIN(start)) FROM zeta.computation");
if (rs.next()) {
days = Math.max(1, rs.getInt(1));
buffer.append(days);
buffer.append(" days</li>");
}
rs.close();
buffer.append(" <ul>\n");
buffer.append(" <li>~");
buffer.append((int)((fpo/(86400.0*days))/1000000000.0));
buffer.append(" GFLOPS</li>\n");
buffer.append(" <li>~");
buffer.append((int)(fpo/7226000000000.0/3600.0));
buffer.append(" hours maximal performance of IBM ASCI White, 8192 Power3 375 MHz processors (place 2, 06/2002, <a href=\"http://www.top500.org/list/2002/06/\">www.top500.org</a>)</li>\n");
buffer.append(" <li>~");
buffer.append((int)(fpo/250000000.0/3600.0/24.0/365.0));
buffer.append(" years maximal performance of one Intel Pentium 4 processor with 2 GHz, 250 MFLOPS</li>\n");
rs = stmt.executeQuery("SELECT DAYS(res.stop),MIN(res.stop),SUM(SQRT((comp.work_unit_id+comp.range)/12.566370614359)*148*1.245*1.246*comp.range) AS flops"
+ " FROM zeta.computation comp,zeta.result res"
+ " WHERE res.task_id=comp.task_id"
+ " AND res.work_unit_id=comp.work_unit_id"
+ " GROUP BY DAYS(res.stop) ORDER BY flops DESC FETCH FIRST 1 ROWS ONLY");
if (rs.next()) {
buffer.append(" </ul>\n<li>Day with best performance (");
days = rs.getInt(1);
buffer.append(dateFormat.format(rs.getTimestamp(2)));
buffer.append("):</li>\n <ul>\n <li>");
double d = fpo = rs.getDouble(3);
int exp = 0;
while (d > 10.0) {
d /= 10.0;
++exp;
}
int n = (int)Math.floor(d);
buffer.append(n);
buffer.append('.');
buffer.append((int)Math.floor((d-n)*10.0));
buffer.append("<font face=\"Symbol\">×</font>10<sup>");
buffer.append(exp);
buffer.append("</sup> floating-point operations for calculating more than ");
rs.close();
rs = stmt.executeQuery("SELECT SUM(CAST(comp.range AS DECIMAL(20, 0)))"
+ " FROM zeta.computation comp,zeta.result res"
+ " WHERE comp.task_id=res.task_id"
+ " AND comp.work_unit_id=res.work_unit_id"
+ " AND DAYS(res.stop)=" + days);
if (rs.next()) {
d = rs.getDouble(1)/1000000000.0;
n = (int)Math.floor(d);
buffer.append(n);
buffer.append('.');
buffer.append((int)Math.floor((d-n)*10.0));
buffer.append(" billion zeros</li>\n");
}
buffer.append(" <li>~");
buffer.append((int)(fpo/3600.0/24.0/1000000000.0));
buffer.append(" GFLOPS</li>\n </ul>");
}
rs.close();
rs = stmt.executeQuery("SELECT DAYS(res.stop),HOUR(res.stop),MIN(res.stop),SUM(SQRT((comp.work_unit_id+comp.range)/12.566370614359)*148*1.245*1.246*comp.range) AS flops"
+ " FROM zeta.computation comp,zeta.result res"
+ " WHERE res.task_id=comp.task_id"
+ " AND res.work_unit_id=comp.work_unit_id"
+ " GROUP BY DAYS(res.stop),HOUR(res.stop)"
+ " ORDER BY flops DESC FETCH FIRST 1 ROWS ONLY");
if (rs.next()) {
buffer.append(" <li>Hour with best performance (");
buffer.append(new SimpleDateFormat("MM/dd/yyyy, hh:00-hh:59 a", Locale.GERMANY).format(rs.getTimestamp(3)));
buffer.append("):</li>\n <ul>\n <li>");
double d = fpo = rs.getDouble(4);
int exp = 0;
while (d > 10.0) {
d /= 10.0;
++exp;
}
int n = (int)Math.floor(d);
buffer.append(n);
buffer.append('.');
buffer.append((int)Math.floor((d-n)*10.0));
buffer.append("<font face=\"Symbol\">×</font>10<sup>");
buffer.append(exp);
buffer.append("</sup> floating-point operations</li>\n<li>~");
buffer.append((int)(fpo/3600.0/1000000000.0));
buffer.append(" GFLOPS</li>\n </ul>");
}
rs.close();
} catch (SQLException e) {
throw new ServletException(e);
} finally {
DatabaseUtils.close(stmt);
}
return buffer.toString();
}
protected String createPage(HttpServletRequest req, Connection con) throws SQLException, ServletException {
String enlarge = req.getParameter("enlarge");
StringBuffer buffer = new StringBuffer(20*1024);
final String[] titles = { "Performance characteristics:", "Summary of the computational results:", "Number of resource providers:",
"Number of computers:", "Reserved zeros:" };
final String[] names = { "performance", "computational_results", "resource_providers", "computers", "reserved_zeros" };
if (enlarge == null) {
enlarge = names[0];
} else {
for (int i = names.length-1; i >= 0; --i) {
if (enlarge.equals(names[i])) {
enlarge = names[i];
break;
} else if (i == 0) {
enlarge = names[i];
break;
}
}
}
for (int i = 0; i < titles.length; ++i) {
if (enlarge == names[i]) {
if (i == 0) {
buffer.append("<tr><td colspan=\"6\" height=\"30pt\" class=\"second-head-gray\">");
buffer.append(titles[i]);
buffer.append("</td></tr>\n");
buffer.append("<tr><td colspan=\"6\">\n");
InnerPageBuffer innerPageBuffer = null;
try {
innerPageBuffer = getInnerPageBuffer();
if (innerPageBuffer != null) {
ByteArrayOutputStream out = new ByteArrayOutputStream(10*1024);
StreamUtils.writeData(innerPageBuffer.buffer, out, false, true);
buffer.append(out.toString("ISO-8859-1"));
}
} catch (IOException ioe) {
} finally {
if (innerPageBuffer != null) {
innerPageBuffer.close();
}
}
buffer.append("</td></tr>\n");
} else {
buffer.append("<tr><td colspan=\"6\">\n");
buffer.append("<p><center><a name=\"");
buffer.append(names[i]);
buffer.append("\"><img src=\"statistic?image=");
buffer.append(names[i]);
buffer.append("\"/ width=\"");
buffer.append(imgWidth);
buffer.append("\" height=\"");
buffer.append(imgHeight);
buffer.append("\"></a></center>\n");
buffer.append("</td></tr>\n");
}
break;
}
}
buffer.append("<tr><td colspan=\"6\"><center><table cellpadding=\"5\" cellspacing=\"5\"><colgroup><col width=\"200\"><col width=\"200\"></colgroup>\n");
int idx = 0;
int prevI = 0;
for (int i = 0; i < titles.length; ++i) {
if (enlarge != names[i]) {
if (idx == 0 || idx == 2) {
buffer.append("<tr>");
}
if (idx <= 1) {
buffer.append("<td><center><b>");
buffer.append(titles[i]);
buffer.append("</b></center></td>");
} else {
buffer.append("<td><p><center><a href=\"statistic?enlarge=");
buffer.append(names[i]);
buffer.append("\"><img src=\"/zeta/images/");
buffer.append(names[i]);
buffer.append(".gif\" width=\"140\" height=\"100\"></a></center></td>");
}
if (idx == 1) {
buffer.append("</tr>\n");
i = prevI-1;
} else if (idx == 3) {
buffer.append("</tr>\n");
}
if (++idx >= 4) {
idx = 0;
}
prevI = i;
}
}
buffer.append("</table></center></td></tr>\n");
return buffer.toString();
}
public BufferedImage createImage(Connection con, String imageName) throws SQLException, ServletException {
if (imageName.equals("computational_results")) {
final String[] verticalAxisLabels = { "Number of computed zeros", "Number of computed zeros per day", "1,000,000,000,000 floating-point operations per day",
"Last record", "First target", "Second target", "Third target", "Fourth target" };
final Paint[] colors = { Color.blue, Color.red, Color.green, Color.orange, new Color(0.0f, 1.0f, 0.0f), new Color(1.0f, 0.5f, 0.0f), new Color(0.0f, 0.0f, 0.5f), new Color(0.0f, 0.75f, 0.75f) };
final int[] weight = { 5, 1, 1 };
final int[][] combination = { {0, 3, 4, 5, 6, 7}, {1}, {2} };
return Charts.generateChart(getImageWidth(imageName), getImageHeight(imageName), "Summary of the computational results", "Date", verticalAxisLabels, colors, weight, combination, Charts.createNumberOfComputedZeros(con));
} else if (imageName.equals("resource_providers")) {
final String[] verticalAxisLabels = { "Number of resource providers", "Number of new resource providers", "Number of active resource providers" };
final Paint[] colors = { Color.blue, Color.red, Color.green };
final int[] weight = { 5, 1, 1 };
final int[][] combination = { {0}, {1}, {2} };
return Charts.generateChart(getImageWidth(imageName), getImageHeight(imageName), "Number of resource providers", "Date", verticalAxisLabels, colors, weight, combination, Charts.createNumberOfParticipants(con));
} else if (imageName.equals("computers")) {
final String[] verticalAxisLabels = { "Number of computers", "Number of new computers", "Number of active computers" };
final Paint[] colors = { Color.blue, Color.red, Color.green };
final int[] weight = { 5, 1, 1 };
final int[][] combination = { {0}, {1}, {2} };
return Charts.generateChart(getImageWidth(imageName), getImageHeight(imageName), "Number of computers", "Date", verticalAxisLabels, colors, weight, combination, Charts.createNumberOfComputers(con));
} else if (imageName.equals("reserved_zeros")) {
final String[] verticalAxisLabels = { "Reserved zeros today (" + (new SimpleDateFormat("MM/dd/yyyy", Locale.GERMANY).format(new Date())) + ')',
"Reserved zeros yesterday", "Number of reserved work units today", "Number of reserved work units yesterday" };
final Paint[] colors = { Color.blue, Color.cyan, Color.red, Color.orange };
final int[] weight = { 6, 1 };
final int[][] combination = { {0, 1}, {2, 3} };
return Charts.generateChart(getImageWidth(imageName), getImageHeight(imageName), "Reserved zeros", "Hour", verticalAxisLabels, colors, weight, combination, Charts.createNewReservedZeros(con, 1));
}
return null;
}
}