use of gov.sandia.n2a.host.Remote in project n2a by frothga.
the class NodeJob method monitorProgress.
public synchronized void monitorProgress() {
if (deleted)
return;
if (complete >= 1 && complete != 3)
return;
// Limit monitoring to no more than once per second.
long elapsed = System.currentTimeMillis() - lastMonitored;
long wait = 1000 - elapsed;
if (wait > 0) {
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
}
}
lastMonitored = System.currentTimeMillis();
float oldComplete = complete;
MNode source = getSource();
Host env = Host.get(source);
Path localJobDir = Host.getJobDir(Host.getLocalResourceDir(), source);
// If job is remote, attempt to grab its state files.
// TODO: handle remote jobs waiting in queue. Plan is to update "started" file with queue status.
Path finished = localJobDir.resolve("finished");
if (!Files.exists(finished) && env instanceof Remote) {
@SuppressWarnings("resource") Remote remote = (Remote) env;
if (remote.isConnected() || remote.isEnabled()) {
try {
Path remoteJobDir = Host.getJobDir(env.getResourceDir(), source);
Path remoteFinished = remoteJobDir.resolve("finished");
// throws an exception if the remote file does not exist
Files.copy(remoteFinished, finished);
} catch (Exception e) {
}
}
}
if (complete == -1) {
Path started = localJobDir.resolve("started");
if (Files.exists(started)) {
complete = 0;
dateStarted = new Date(Host.lastModified(started));
lastActive = dateStarted.getTime();
}
}
Backend simulator = Backend.getBackend(source.get("backend"));
if (complete >= 0 && complete < 1) {
float percentDone = 0;
if (expectedSimTime == 0)
expectedSimTime = new UnitValue(source.get("duration")).get();
if (expectedSimTime > 0)
percentDone = (float) (simulator.currentSimTime(source) / expectedSimTime);
if (Files.exists(finished)) {
checkFinished(finished);
} else {
try {
long currentTime = System.currentTimeMillis();
if (simulator.isActive(source)) {
lastActive = currentTime;
} else if (currentTime - lastActive > activeTimeout) {
if (percentDone < 1) {
// Give it up for dead.
Files.copy(new ByteArrayInputStream("dead".getBytes("UTF-8")), finished);
complete = 4;
} else // Job appears to be actually finished, even though "finished" hasn't been written yet.
{
// Fake the "finished" file. This might be overwritten later by the batch process.
// Most likely, it will also report that we succeeded, so presume that things are fine.
Files.copy(new ByteArrayInputStream("success".getBytes("UTF-8")), finished);
complete = 1;
}
}
} catch (Exception e) {
}
}
if (complete >= 0 && complete < 1)
complete = Math.min(0.99999f, percentDone);
}
if (complete == 3) {
// Check if process is still lingering
if (!simulator.isActive(source))
complete = 4;
}
PanelRun panelRun = PanelRun.instance;
PanelStudy panelStudy = PanelStudy.instance;
// Probably running headless, so skip all UI updates.
if (panelRun == null)
return;
if (complete != oldComplete) {
EventQueue.invokeLater(new Runnable() {
public void run() {
panelRun.model.nodeChanged(NodeJob.this);
if (panelRun.displayNode == NodeJob.this) {
panelRun.buttonStop.setEnabled(complete < 1 || complete == 3);
panelRun.viewJob(true);
} else if (panelRun.displayNode instanceof NodeFile && panelRun.displayNode.getParent() == NodeJob.this) {
panelRun.buttonStop.setEnabled(complete < 1 || complete == 3);
// Update the display every 5 seconds during the run.
// Some displays, such as a chart, could take longer than 5s to construct, so don't interrupt those.
// Always update the display when a run finishes.
long currentTime = System.currentTimeMillis();
if (complete >= 1 && complete != 3 || panelRun.displayThread == null && currentTime - lastDisplay > 5000) {
lastDisplay = currentTime;
panelRun.viewFile(true);
}
}
// panelStudy could be null for a brief moment during startup
if (panelStudy != null)
panelStudy.tableSamples.updateJob(key);
}
});
}
if (!panelRun.tree.isCollapsed(new TreePath(getPath())))
build(panelRun.tree);
}
use of gov.sandia.n2a.host.Remote in project n2a by frothga.
the class Main method runHeadless.
/**
* Assumes this app was started solely for the purpose of running one specific job.
* This job operates outside the normal job management. The user is responsible
* for everything, including load balancing, directory and file management.
* Jobs can run remotely, but there is no support for retrieving results.
*/
public static void runHeadless(MNode record) {
// See PanelEquations.launchJob()
// Use current working directory, on assumption that's what the caller wants.
Path jobDir = Paths.get(System.getProperty("user.dir")).toAbsolutePath();
// This allows a remote job to run in the regular jobs directory there.
String jobKey = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.ROOT).format(new Date());
// Make this appear as if it is from the jobs collection.
MDoc job = new MDoc(jobDir.resolve("job"), jobKey);
String key = record.key();
MNode doc = AppData.models.childOrEmpty(key);
record.mergeUnder(doc);
// TODO: the only reason to collate here is to ensure that host and backend are correctly identified if they are inherited. Need a more efficient method, such as lazy collation in MPart.
MPart collated = new MPart(record);
NodeJob.collectJobParameters(collated, key, job);
NodeJob.saveSnapshot(record, job);
// Handle remote host
// If a remote host is used, it must be specified exactly, rather than a list of possibilities.
Host host = Host.get(job);
if (// Need to note the key so user can easily find the remote job directory.
host instanceof Remote) {
job.set(jobKey, "remoteKey");
job.save();
}
// Start the job.
Backend backend = Backend.getBackend(job.get("backend"));
backend.start(job);
// Wait for completion
NodeJob node = new NodeJobHeadless(job);
while (node.complete < 1) node.monitorProgress();
// Convert to CSV, if requested.
if (record.getFlag("$metadata", "csv")) {
Table table = new Table(jobDir.resolve("out"), false);
try {
table.dumpCSV(jobDir.resolve("out.csv"));
} catch (IOException e) {
}
}
// Extract results requested in ASV
MNode ASV = record.child("$metadata", "dakota", "ASV");
// nothing more to do
if (ASV == null)
return;
OutputParser output = new OutputParser();
output.parse(jobDir.resolve("out"));
try (BufferedWriter writer = Files.newBufferedWriter(jobDir.resolve("results"))) {
for (MNode o : ASV) {
String name = o.get();
Column c = output.getColumn(name);
float value = 0;
if (c != null && !c.values.isEmpty())
value = c.values.get(c.values.size() - 1);
writer.write(value + " " + name);
}
} catch (IOException e) {
}
}
use of gov.sandia.n2a.host.Remote in project n2a by frothga.
the class PanelEquations method launchJob.
public void launchJob() {
if (record == null)
return;
prepareForTabChange();
String jobKey = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.ROOT).format(new Date());
MDoc job = (MDoc) AppData.runs.childOrCreate(jobKey);
NodeJob.collectJobParameters(root.source, record.key(), job);
// Force directory (and job file) to exist, so Backends can work with the dir.
job.save();
NodeJob.saveSnapshot(record, job);
MainTabbedPane mtp = (MainTabbedPane) MainFrame.instance.tabs;
mtp.setPreferredFocus(PanelRun.instance, PanelRun.instance.tree);
mtp.selectTab("Runs");
NodeJob node = PanelRun.instance.addNewRun(job, true);
// Hack to allow local jobs to bypass the wait-for-host queue.
// It would be better for all jobs to check for resources before starting.
// However, the time cost for the local check could be as long as the job itself
// (for very simple models). There is some expectation that the user knows
// the state of their own system when they choose to hit the play button.
Backend backend = Backend.getBackend(job.get("backend"));
String backendName = backend.getName().toLowerCase();
Host h = Host.get(job);
boolean internal = backend instanceof InternalBackend;
boolean localhost = !(h instanceof Remote);
boolean forbidden = h.config.get("backend", backendName).equals("0");
if (// use of Internal overrides host selection
internal || (localhost && !forbidden)) {
// In case it was "internal" but not "localhost", set host to correct value.
job.set("localhost", "host");
backend.start(job);
h.monitor(node);
return;
}
Host.waitForHost(node);
}
use of gov.sandia.n2a.host.Remote in project n2a by frothga.
the class NodeJob method build.
/**
* Construct the list of resources under this job node.
* This only called if this job node is actively monitored and open in the tree,
* or if this job node is about to be opened regardless of monitoring.
*
* This function may make blocking remote calls, so should not run on the EDT.
* It queues changes and inserts an EDT event to apply them.
*/
public synchronized void build(JTree tree) {
NodeBase selected = null;
TreePath path = tree.getLeadSelectionPath();
if (path != null)
selected = (NodeBase) path.getLastPathComponent();
TreeMap<String, NodeFile> existing = new TreeMap<String, NodeFile>();
if (children != null) {
for (Object c : children) {
NodeFile nf = (NodeFile) c;
nf.found = false;
existing.put(nf.path.getFileName().toString(), nf);
}
}
// Scan local job dir
boolean changed = false;
MNode source = getSource();
Path localJobDir = Host.getJobDir(Host.getLocalResourceDir(), source);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(localJobDir)) {
for (Path file : dirStream) if (buildChild(file, existing))
changed = true;
} catch (IOException e) {
}
// Update display immediately, before waiting on remote.
if (changed)
applyChanges(tree, selected, existing);
changed = false;
// Scan remote job dir. Because this is done second, remote files take lower precedence than local files.
Host env = Host.get(source);
if (env instanceof Remote) {
try {
// To get here, the use had to expand the node. This implies permission to prompt for login.
((Remote) env).enable();
Path remoteJobDir = Host.getJobDir(env.getResourceDir(), source);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(remoteJobDir)) {
for (Path file : dirStream) if (buildChild(file, existing))
changed = true;
}
} catch (Exception e) {
}
}
List<String> keys = new ArrayList<String>(existing.keySet());
for (String key : keys) {
NodeFile nf = existing.get(key);
if (!nf.found) {
changed = true;
existing.remove(key);
}
}
if (changed)
applyChanges(tree, selected, existing);
}
use of gov.sandia.n2a.host.Remote in project n2a by frothga.
the class SettingsHost method getPanel.
@Override
public Component getPanel() {
if (scrollPane != null)
return scrollPane;
JPanel view = new JPanel();
scrollPane = new JScrollPane(view);
// About one line of text. Typically, one "click" of the wheel does 3 steps, so about 45px or 3 lines of text.
scrollPane.getVerticalScrollBar().setUnitIncrement(15);
for (Host h : Host.getHosts()) if (h instanceof Remote)
model.addElement(h);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setToolTipText("Press Insert to create host. Press Delete to remove host.");
InputMap inputMap = list.getInputMap();
inputMap.put(KeyStroke.getKeyStroke("INSERT"), "add");
inputMap.put(KeyStroke.getKeyStroke("ctrl shift EQUALS"), "add");
inputMap.put(KeyStroke.getKeyStroke("DELETE"), "delete");
inputMap.put(KeyStroke.getKeyStroke("BACK_SPACE"), "delete");
ActionMap actionMap = list.getActionMap();
actionMap.put("add", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// Create new record
String hostname = Host.uniqueName();
// Get default class. The user can change it later.
Host h = Host.create(hostname, "");
// Focus record in UI
int index = list.getSelectedIndex();
if (index < 0)
index = model.getSize();
model.add(index, h);
// Assumption: this triggers a selection change event, which will in turn call displayRecord().
list.setSelectedIndex(index);
fieldName.requestFocusInWindow();
}
});
actionMap.put("delete", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// Remove current record
int index = list.getSelectedIndex();
Host h = list.getSelectedValue();
if (h == null)
return;
Host.remove(h, true);
// Focus another record, or clear UI
model.remove(index);
index = Math.min(index, model.size() - 1);
// triggers selection change event, resulting in call to displayRecord()
if (index >= 0)
list.setSelectedIndex(index);
}
});
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting())
return;
displayRecord();
}
});
fieldName = new MTextField(null, "", "", 20, true);
fieldName.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
Host h = list.getSelectedValue();
String newName = fieldName.getText();
Host.rename(h, newName);
list.repaint();
if (editor instanceof NameChangeListener)
((NameChangeListener) editor).nameChanged(h.name);
}
});
for (ExtensionPoint ext : PluginManager.getExtensionsForPoint(Factory.class)) {
Factory f = (Factory) ext;
if (f instanceof FactoryRemote)
comboClass.addItem(f.className());
}
comboClass.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newClass = comboClass.getSelectedItem().toString();
// Change the class. This requires destroying the current instance and constructing
// a new one that is bound to the same record.
int index = list.getSelectedIndex();
Host h = list.getSelectedValue();
if (h == null)
return;
String originalClass = h.getClassName();
if (newClass.equals(originalClass))
return;
Host.remove(h, false);
Host h2 = Host.create(h.name, newClass);
h.transferJobsTo(h2);
model.set(index, h2);
displayRecord();
}
});
editorHolder.setLayout(new BorderLayout());
JPanel panelList = Lay.BL("C", list, "pref=[100,200]");
panelList.setBorder(LineBorder.createBlackLineBorder());
panelList = (JPanel) Lay.eb(Lay.BL("C", panelList), "5");
Lay.BLtg(view, "N", Lay.BL("W", Lay.BxL("H", Lay.BL("N", panelList), Box.createHorizontalStrut(5), Lay.BL("N", Lay.BxL(Lay.FL(Lay.lb("Name"), fieldName), Lay.FL(Lay.lb("Class"), comboClass), editorHolder)))));
scrollPane.setFocusCycleRoot(true);
if (list.getModel().getSize() > 0)
list.setSelectedIndex(0);
return scrollPane;
}
Aggregations