/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Regression.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool;
import com.sun.electric.Main;
import com.sun.electric.database.EObjectOutputStream;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.Snapshot;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.EDatabase;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.id.IdManager;
import com.sun.electric.database.id.IdReader;
import com.sun.electric.database.text.Pref;
import com.sun.electric.database.text.Setting;
import com.sun.electric.database.text.Version;
import com.sun.electric.technology.TechFactory;
import com.sun.electric.technology.Technology;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.generator.layout.LayoutLib;
import com.sun.electric.tool.lang.EvalJavaBsh;
import com.sun.electric.tool.user.ErrorLogger;
import com.sun.electric.tool.user.MessagesStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
/**
* Simple client for regressions.
*/
public class Regression {
public static boolean runScript(Process process, String script) {
Pref.forbidPreferences();
IdReader reader = null;
Snapshot currentSnapshot = IdManager.stdIdManager.getInitialSnapshot();
// EDatabase database = new EDatabase(currentSnapshot);
// EDatabase.setClientDatabase(database);
System.out.println("Running " + script);
try {
InputStream inStream = process.getInputStream();
OutputStream outStream = process.getOutputStream();
InputStream errStream = process.getErrorStream();
new ExecProcessReader(errStream).start();
reader = new IdReader(new DataInputStream(new BufferedInputStream(inStream)), IdManager.stdIdManager);
int protocolVersion = reader.readInt();
if (protocolVersion != Job.PROTOCOL_VERSION) {
System.out.println("Client's protocol version " + Job.PROTOCOL_VERSION + " is incompatible with Server's protocol version " + protocolVersion);
for (int i = 0; i < 100; i++)
System.out.print((char)reader.readByte());
System.out.println();
return false;
}
int connectionId = reader.readInt();
System.out.format("%1$tT.%1$tL ", Calendar.getInstance());
System.out.println("Connected id="+connectionId);
DataOutputStream clientOutputStream = new DataOutputStream(new BufferedOutputStream(outStream));
writeServerJobs(clientOutputStream, connectionId, script);
clientOutputStream.close();
int curJobId = -1;
AbstractUserInterface ui = new Main.UserInterfaceDummy();
ui.patchConnectionId(connectionId);
boolean passed = true;
for (;;) {
byte tag = reader.readByte();
long timeStamp = reader.readLong();
// System.out.format("%1$tT.%1$tL->%2$tT.%2$tL %3$2d ", timeStamp, Calendar.getInstance(), tag);
if (tag == 1) {
currentSnapshot = Snapshot.readSnapshot(reader, currentSnapshot);
System.out.println("Snapshot received " + currentSnapshot.snapshotId);
// database.lock(true);
// try {
// database.lowLevelSetCanUndoing(true);
// database.undo(currentSnapshot);
// database.lowLevelSetCanUndoing(false);
// } finally {
// database.unlock();
// }
// System.out.format(" ->%1$tT.%1$tL Database updated to snapshot %2$d\n", Calendar.getInstance(), currentSnapshot.snapshotId);
} else {
Client.ServerEvent serverEvent = Client.read(reader, tag, timeStamp, ui, currentSnapshot);
if (serverEvent instanceof Client.EJobEvent) {
Client.EJobEvent e = (Client.EJobEvent)serverEvent;
int jobId = e.jobKey.jobId;
assert e.newState == EJob.State.SERVER_DONE;
if (jobId > 0) {
if (!e.doItOk) {
System.out.println("Job " + e.jobName + " failed");
// printErrorStream(process);
// ui.saveMessages(null);
passed = false;
}
continue;
}
assert jobId == curJobId;
// EJob ejob = new EJob(client, jobId, e.jobType, e.jobName, e.serializedJob);
// ejob.serializedResult = e.serializedResult;
// Throwable result = ejob.deserializeResult();
// assert e.doItOk == (result == null);
if (!e.doItOk) {
System.out.println("Job " + e.jobName + " exception");
// System.out.println(result);
// result.printStackTrace(System.out);
// printErrorStream(process);
// ui.saveMessages(null);
passed = false;
} else {
System.out.println("Job " + jobId + " ok");
}
switch (jobId) {
case -1:
curJobId = -2;
// job = script.equals("CRASH") ? new CrashJob() : EvalJavaBsh.runScriptJob(script);
// job.ejob.jobKey = new Job.Key(connectionId, --curJobId, true);
// writeJob(clientOutputStream, job);
break;
case -2:
curJobId = -3;
// job = new QuitJob();
// job.ejob.jobKey = new Job.Key(connectionId, --curJobId, true);
// writeJob(clientOutputStream, job);
break;
// case -3:
// ui.saveMessages(null);
// return passed;
default:
}
} else {
serverEvent.show(ui);
if (serverEvent instanceof Client.ShutdownEvent) {
assert curJobId == -3;
ui.saveMessages(null);
return passed;
}
}
}
}
} catch (IOException e) {
reader = null;
System.out.println("END OF FILE reading from server");
// printErrorStream(process);
try {
Thread.sleep(1000);
System.out.println("Server exit code="+process.exitValue());
process.getOutputStream().close();
} catch (Exception e1) {
e1.printStackTrace(System.out);
}
return false;
}
}
private static void printErrorStream(Process process) {
try {
// process.getOutputStream().close();
InputStream errStream = new BufferedInputStream(process.getErrorStream());
System.out.println("<StdErr>");
for (;;) {
if (errStream.available() == 0) break;
int c = errStream.read();
if (c < 0) break;
System.out.print((char)c);
}
System.out.println("</StdErr>");
} catch (IOException e) {
e.printStackTrace();
}
}
private static class InitJob extends Job {
private InitJob() {
super("InitJob", null, Job.Type.CHANGE, null, null, Job.Priority.USER);
}
public boolean doIt() throws JobException {
database.setToolSettings((Setting.RootGroup)ToolSettings.getToolSettings(""));
assert database.getGeneric() == null;
Generic generic = Generic.newInstance(database.getIdManager());
database.addTech(generic);
for (TechFactory techFactory: TechFactory.getKnownTechs().values()) {
Map<TechFactory.Param,Object> paramValues = Collections.emptyMap();
Technology tech = techFactory.newInstance(generic, paramValues);
if (tech != null)
database.addTech(tech);
}
// EditingPreferences.setThreadEditingPreferences(new EditingPreferences(true, database.getTechPool()));
return true;
}
}
private static class CrashJob extends Job {
protected CrashJob() {
super("CrashTest", null, Job.Type.CHANGE, null, null, Job.Priority.USER);
}
public boolean doIt() throws JobException {
String regressionname = "qFourP2-electric-final-jelib";
String libname = "qFourP2.jelib";
String cellname = "qFourP1top";
String rootPath = "../../";
boolean caching = true;
String logname = "output/"+libname+"_"+cellname+"_LE_"+(caching ? "C" : "NC")+"-"+Version.getVersion()+".log";
MessagesStream.getMessagesStream().save(logname);
Library rootLib = LayoutLib.openLibForRead(rootPath+"data/"+regressionname+"/"+libname);
ErrorLogger repairLogger = ErrorLogger.newInstance("Repair Libraries");
for (Iterator it = Library.getLibraries(); it.hasNext(); ) {
Library lib = (Library)it.next();
lib.checkAndRepair(true, repairLogger);
}
System.out.println("Repair Libraries: " + repairLogger.getNumErrors() + " errors," + repairLogger.getNumWarnings() + " warnings");
Cell lay = rootLib.findNodeProto(cellname+"{sch}");
System.out.println("Cell = "+lay);
return true;
}
}
private static class QuitJob extends Job {
private QuitJob() {
super("QuitJob", null, Job.Type.CHANGE, null, null, Job.Priority.USER);
}
public boolean doIt() throws JobException {
Client.fireServerEvent(new Client.ShutdownEvent());
return true;
}
}
public static void main(String[] args) {
makeCrashInput(args[0]);
}
private static void makeCrashInput(String fileName) {
try {
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
writeServerJobs(out, 0, "CRASH");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeServerJobs(DataOutputStream clientOutputStream, int connectionId, String script) throws IOException {
EDatabase database = new EDatabase(IdManager.stdIdManager.getInitialEnvironment());
Job.setUserInterface(new UserInterfaceInitial(database));
Job job1 = new InitJob();
job1.ejob.jobKey = new Job.Key(connectionId, -1, true);
Job job2 = script.equals("CRASH") ? new CrashJob() : EvalJavaBsh.runScriptJob(script);
job2.ejob.jobKey = new Job.Key(connectionId, -2, true);
Job job3 = new QuitJob();
job3.ejob.jobKey = new Job.Key(connectionId, -3, true);
writeEditingPreferences(clientOutputStream, database);
writeJob(clientOutputStream, job1);
writeJob(clientOutputStream, job2);
writeJob(clientOutputStream, job3);
}
private static void writeEditingPreferences(DataOutputStream clientOutputStream, EDatabase database) throws IOException {
EditingPreferences ep = new EditingPreferences(true, database.getTechPool());
byte[] serializedEp;
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream out = new EObjectOutputStream(byteStream, database);
out.writeObject(ep);
out.flush();
serializedEp = byteStream.toByteArray();
} catch (Throwable e) {
e.printStackTrace();
return;
}
clientOutputStream.writeByte((byte)2);
clientOutputStream.writeInt(serializedEp.length);
clientOutputStream.write(serializedEp);
}
private static void writeJob(DataOutputStream clientOutputStream, Job job) throws IOException {
EJob ejob = job.ejob;
ejob.serialize(EDatabase.clientDatabase());
clientOutputStream.writeByte((byte)1);
clientOutputStream.writeInt(ejob.jobKey.jobId);
clientOutputStream.writeUTF(ejob.jobType.toString());
clientOutputStream.writeUTF(ejob.jobName);
clientOutputStream.writeInt(ejob.serializedJob.length);
clientOutputStream.write(ejob.serializedJob);
clientOutputStream.flush();
}
/**
* This class is used to read data from an external process.
* If something does not consume the data, it will fill up the default
* buffer and deadlock. This class also redirects data read
* from the process (the process' output) to another stream,
* if specified.
*/
public static class ExecProcessReader extends Thread {
private InputStream in;
private char [] buf;
/**
* Create a stream reader that will read from the stream, and
* store the read text into buffer.
* @param in the input stream
*/
public ExecProcessReader(InputStream in) {
this.in = in;
buf = new char[256];
setName("ExecProcessReader");
}
public void run() {
try {
// read from stream
InputStreamReader reader/*input*/ = new InputStreamReader(in);
// BufferedReader reader = new BufferedReader(input);
int read = 0;
while ((read = reader.read(buf)) >= 0) {
String s = new String(buf, 0, read);
Calendar c = Calendar.getInstance();
System.err.print(s);
System.out.format("%1$tT.%1$tL <err> %2$s </err>\n", c, s);
}
reader.close();
// input.close();
} catch (java.io.IOException e) {
e.printStackTrace();
e.printStackTrace(System.out);
}
}
}
}