package org.yamcs.parameter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.yamcs.ConfigurationException; import org.yamcs.YConfiguration; import org.yamcs.YamcsServer; import org.yamcs.tctm.ParameterDataLinkInitialiser; import org.yamcs.time.TimeService; import org.yamcs.utils.LoggingUtils; import org.yamcs.utils.ValueUtility; import org.yamcs.xtce.NameDescription; import org.yamcs.xtce.Parameter; import org.yamcs.xtce.XtceDb; import org.yamcs.yarch.DataType; import org.yamcs.yarch.Stream; import org.yamcs.yarch.Tuple; import org.yamcs.yarch.TupleDefinition; import org.yamcs.yarch.YarchDatabase; import com.google.common.util.concurrent.AbstractService; /** * Collects each second system processed parameters from whomever registers and sends them on the sys_var stream * * * @author nm * */ public class SystemParametersCollector extends AbstractService implements Runnable { static Map<String,SystemParametersCollector> instances=new HashMap<String,SystemParametersCollector>(); static long frequencyMillisec=1000; List<SystemParametersProducer> providers = new CopyOnWriteArrayList<SystemParametersProducer>(); static final String STREAM_NAME = "sys_param"; private String spJvmTotalMemory; private String spJvmMemoryUsed; private String spJvmTheadCount; public static final int JVM_COLLECTION_INTERVAL = 10; private boolean provideJvmVariables = false; private int jvmCollectionCountdown = 0; ScheduledThreadPoolExecutor timer; final Stream stream; int seqCount = 0; private final Logger log; private final String namespace; private final String serverId; final String instance; TimeService timeService; static public SystemParametersCollector getInstance(String instance) { synchronized(instances) { return instances.get(instance); } } public SystemParametersCollector(String instance) throws ConfigurationException { this(instance, null); } public SystemParametersCollector(String instance, Map<String, Object> args) throws ConfigurationException { this.instance = instance; log = LoggingUtils.getLogger(this.getClass(), instance); processArgs(args); YarchDatabase ydb = YarchDatabase.getInstance(instance); Stream s = ydb.getStream(STREAM_NAME); if(s==null) { throw new ConfigurationException("Stream '"+STREAM_NAME+"' does not exist"); } stream = s; timeService = YamcsServer.getInstance(instance).getTimeService(); serverId = YamcsServer.getServerId(); namespace = XtceDb.YAMCS_SPACESYSTEM_NAME+NameDescription.PATH_SEPARATOR+serverId; log.debug("Using {} as serverId, and {} as namespace for system parameters", serverId, namespace); if(provideJvmVariables) { spJvmTotalMemory = namespace+"/jvmTotalMemory"; log.debug("publishing jvmTotalMemory with parameter id {}", spJvmTotalMemory); spJvmMemoryUsed = namespace+"/jvmMemoryUsed"; log.debug("publishing jvmMemoryUsed with parameter id {}", spJvmMemoryUsed); spJvmTheadCount = namespace+"/jvmThreadCount"; log.debug("publishing jvmThreadCount with parameter id {}", spJvmTheadCount); } synchronized(instances) { instances.put(instance, this); } } private void processArgs(Map<String, Object> args) { if(args==null) { return; } if(args.containsKey("provideJvmVariables")) { provideJvmVariables = YConfiguration.getBoolean(args, "provideJvmVariables"); } } @Override public void doStart() { timer = new ScheduledThreadPoolExecutor(1); timer.scheduleAtFixedRate(this, 1000L, frequencyMillisec, TimeUnit.MILLISECONDS); notifyStarted(); } @Override public void doStop() { timer.shutdown(); notifyStopped(); } /** * Run from the timer, collect all parameters and send them on the stream */ @Override public void run() { List<ParameterValue> params = new ArrayList<ParameterValue>(); if(provideJvmVariables) { jvmCollectionCountdown--; if(jvmCollectionCountdown<=0) { collectJvmParameters(params); jvmCollectionCountdown = JVM_COLLECTION_INTERVAL; } } for(SystemParametersProducer p: providers) { try { Collection<ParameterValue> pvc =p.getSystemParameters(); params.addAll(pvc); } catch (Exception e) { log.warn("Error getting parameters from provider {}", p, e); } } long gentime = timeService.getMissionTime(); if(params.isEmpty()) { return; } TupleDefinition tdef=ParameterDataLinkInitialiser.PARAMETER_TUPLE_DEFINITION.copy(); List<Object> cols=new ArrayList<Object>(4+params.size()); cols.add(gentime); cols.add(namespace); cols.add(seqCount); cols.add(timeService.getMissionTime()); for(ParameterValue pv:params) { String name = pv.getParameterQualifiedNamed(); int idx=tdef.getColumnIndex(name); if(idx!=-1) { log.warn("duplicate value for {}\nfirst: {}\n second: {}", name, cols.get(idx), pv); continue; } tdef.addColumn(name, DataType.PARAMETER_VALUE); cols.add(pv); } Tuple t=new Tuple(tdef, cols); stream.emitTuple(t); } private void collectJvmParameters(List<ParameterValue> params) { long time = timeService.getMissionTime(); Runtime r = Runtime.getRuntime(); ParameterValue jvmTotalMemory = SystemParametersCollector.getPV(spJvmTotalMemory, time, r.totalMemory()/1024); ParameterValue jvmMemoryUsed = SystemParametersCollector.getPV(spJvmMemoryUsed, time, (r.totalMemory()-r.freeMemory())/1024); ParameterValue jvmThreadCount = SystemParametersCollector.getUnsignedIntPV(spJvmTheadCount, time, Thread.activeCount()); params.add(jvmTotalMemory); params.add(jvmMemoryUsed); params.add(jvmThreadCount); } public void registerProvider(SystemParametersProducer p, Collection<Parameter> params) { log.debug("Registering system variables provider {}", p); providers.add(p); } /** * this is the namespace all system parameters should be in * * @return the namespace to be used by the system parameters */ public String getNamespace() { return namespace; } public static ParameterValue getNewPv(String fqn, long time) { ParameterValue pv = new ParameterValue(fqn); pv.setAcquisitionTime(time); pv.setGenerationTime(time); return pv; } public static ParameterValue getPV(String fqn, long time, String v) { ParameterValue pv = getNewPv(fqn, time); pv.setEngValue(ValueUtility.getStringValue(v)); return pv; } public static ParameterValue getPV(String fqn, long time, double v) { ParameterValue pv = getNewPv(fqn, time); pv.setEngValue(ValueUtility.getDoubleValue(v)); return pv; } public static ParameterValue getPV(String fqn, long time, boolean v) { ParameterValue pv = getNewPv(fqn, time); pv.setEngValue(ValueUtility.getBooleanValue(v)); return pv; } public static ParameterValue getPV(String fqn, long time, long v) { ParameterValue pv = getNewPv(fqn, time); pv.setEngValue(ValueUtility.getSint64Value(v)); return pv; } public static ParameterValue getUnsignedIntPV(String fqn, long time, int v) { ParameterValue pv = getNewPv(fqn, time); pv.setEngValue(ValueUtility.getUint64Value(v)); return pv; } }