package water.util;
import water.H2O;
import water.Iced;
import water.MRTask;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class ProfileCollectorTask extends MRTask<ProfileCollectorTask> {
// helper class to store per-node profiles
public static class NodeProfile extends Iced {
NodeProfile(int len) {
stacktraces = new String[len];
counts = new int[len];
}
public String node_name;
public long timestamp;
public String[] stacktraces;
public int[] counts;
}
public ProfileCollectorTask(int stack_depth) { super(H2O.GUI_PRIORITY); _stack_depth = stack_depth; }
// input
public final int _stack_depth;
// output
public NodeProfile[] _result;
@Override public void reduce(ProfileCollectorTask that) {
for (int i=0; i<_result.length; ++i)
if (_result[i] == null)
_result[i] = that._result[i];
}
/**
* This runs on each node in the cluster.
*/
@Override public void setupLocal() {
int idx = H2O.SELF.index();
_result = new NodeProfile[H2O.CLOUD.size()];
Map<String, Integer> countedStackTraces = new HashMap<>();
final int repeats = 100;
for (int i=0; i<repeats; ++i) {
Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> el : allStackTraces.entrySet()) {
StringBuilder sb = new StringBuilder();
int j=0;
for (StackTraceElement ste : el.getValue()) {
String val = ste.toString();
// filter out unimportant stuff
if( j==0 && ( val.equals("sun.misc.Unsafe.park(Native Method)")
|| val.equals("java.lang.Object.wait(Native Method)")
|| val.equals("java.lang.Thread.sleep(Native Method)")
|| val.equals("java.lang.Thread.yield(Native Method)")
|| val.equals("java.net.PlainSocketImpl.socketAccept(Native Method)")
|| val.equals("sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)")
|| val.equals("sun.nio.ch.DatagramChannelImpl.receive0(Native Method)")
|| val.equals("java.lang.Thread.dumpThreads(Native Method)")
) ) { break; }
sb.append(ste.toString());
sb.append("\n");
j++;
if (j==_stack_depth) break;
}
String st = sb.toString();
boolean found = false;
for (Map.Entry<String, Integer> entry : countedStackTraces.entrySet()) {
if (entry.getKey().equals(st)) {
entry.setValue(entry.getValue() + 1);
found = true;
break;
}
}
if (!found) countedStackTraces.put(st, 1);
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int i=0;
_result[idx] = new NodeProfile(countedStackTraces.size());
_result[idx].node_name = H2O.getIpPortString();
_result[idx].timestamp = System.currentTimeMillis();
for (Map.Entry<String, Integer> entry : countedStackTraces.entrySet()) {
_result[idx].stacktraces[i] = entry.getKey();
_result[idx].counts[i] = entry.getValue();
i++;
}
// sort it
Map<Integer, String> sorted = new TreeMap<>(Collections.reverseOrder());
for (int j=0; j<_result[idx].counts.length; ++j) {
if (_result[idx].stacktraces[j] != null && _result[idx].stacktraces[j].length() > 0)
sorted.put(_result[idx].counts[j], _result[idx].stacktraces[j]);
}
// overwrite results
String[] sorted_stacktraces = new String[sorted.entrySet().size()];
int[] sorted_counts = new int[sorted.entrySet().size()];
i=0;
for (Map.Entry<Integer, String> e : sorted.entrySet()) {
sorted_stacktraces[i] = e.getValue();
sorted_counts[i] = e.getKey();
i++;
}
_result[idx].stacktraces = sorted_stacktraces;
_result[idx].counts = sorted_counts;
}
}