# HG changeset patch # User Roman Kennke # Date 1358287252 -3600 # Node ID 6815308bb3624f4690de0d0d7e1ed5cb06468c3b # Parent 6da66da9e8ac526fb8bb4444c98cbeabd8734ad1 Initial NUMA agent. Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005182.html diff -r 6da66da9e8ac -r 6815308bb362 agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java --- a/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/agent/core/src/main/java/com/redhat/thermostat/backend/Backend.java Tue Jan 15 23:00:52 2013 +0100 @@ -55,9 +55,7 @@ protected DAOFactory df = null; private boolean observeNewJvm = attachToNewProcessByDefault(); - private String version; - private String vendor; - private String description; + private Map config = new HashMap<>(); private BackendID id; @@ -92,7 +90,9 @@ setDAOFactoryAction(); } - protected abstract void setDAOFactoryAction(); + protected void setDAOFactoryAction() { + // Default implementation does nothing. + } /** * Set the named configuration to the given value. @@ -112,25 +112,10 @@ * for this backend or the value is not valid for the key */ protected void setConfigurationValue(String name, String value) { - - if (name.equals(BackendsProperties.DESCRIPTION.name())) { - this.description = value; - } else if (name.equals(BackendsProperties.VERSION.name())) { - this.version = value; - } else if (name.equals(BackendsProperties.VENDOR.name())) { - this.vendor = value; - } else { - setConfigurationValueImpl(name, value); - } + config.put(name, value); } /** - * Set the named configuration to the given value. - * By default, does nothing. - */ - protected void setConfigurationValueImpl(String name, String value) {} - - /** * @return the name of the {@link Backend} */ public String getName() { @@ -141,21 +126,21 @@ * @returns the description of the {@link Backend} */ public String getDescription() { - return description; + return config.get(BackendsProperties.DESCRIPTION.name()); } /** * @return the vendor of the {@link Backend} */ public String getVendor() { - return vendor; + return config.get(BackendsProperties.VENDOR.name()); } /** * @return the version of the {@link Backend} */ public String getVersion() { - return version; + return config.get(BackendsProperties.VERSION.name()); } /** Get a map containing the current settings of this backend. @@ -176,7 +161,9 @@ * @throws IllegalArgumentException if the key does not refer to a valid configuration option for * this backend */ - public abstract String getConfigurationValue(String key); + public String getConfigurationValue(String key) { + return config.get(key); + } /** * Activate the {@link Backend}. Based on the current configuration, @@ -246,6 +233,8 @@ @Override public int hashCode() { + String vendor = getVendor(); + String version = getVersion(); final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); @@ -256,6 +245,8 @@ @Override public boolean equals(Object obj) { + String vendor = getVendor(); + String version = getVersion(); if (this == obj) return true; if (obj == null) @@ -269,21 +260,21 @@ } else if (!id.equals(other.id)) return false; if (vendor == null) { - if (other.vendor != null) + if (other.getVendor() != null) return false; - } else if (!vendor.equals(other.vendor)) + } else if (!vendor.equals(other.getVendor())) return false; if (version == null) { - if (other.version != null) + if (other.getVersion() != null) return false; - } else if (!version.equals(other.version)) + } else if (!version.equals(other.getVersion())) return false; return true; } @Override public String toString() { - return "Backend [version=" + version + ", vendor=" + vendor - + ", description=" + description + ", id=" + id + "]"; + return "Backend [version=" + getVersion() + ", vendor=" + getVendor() + + ", description=" + getDescription() + ", id=" + id + "]"; } } diff -r 6da66da9e8ac -r 6815308bb362 distribution/config/commands/agent.properties --- a/distribution/config/commands/agent.properties Thu Jan 10 21:48:04 2013 +0100 +++ b/distribution/config/commands/agent.properties Tue Jan 15 23:00:52 2013 +0100 @@ -30,6 +30,8 @@ thermostat-gc-remote-collector-common-@project.version@.jar, \ thermostat-gc-remote-collector-command-@project.version@.jar, \ thermostat-storage-mongodb-${project.version}.jar, \ + thermostat-numa-common-${project.version}.jar, \ + thermostat-numa-agent-${project.version}.jar, \ mongo.jar, \ commons-beanutils.jar, \ commons-codec.jar, \ diff -r 6da66da9e8ac -r 6815308bb362 distribution/pom.xml --- a/distribution/pom.xml Thu Jan 10 21:48:04 2013 +0100 +++ b/distribution/pom.xml Tue Jan 15 23:00:52 2013 +0100 @@ -586,5 +586,10 @@ ${project.version} + + com.redhat.thermostat + thermostat-numa-agent + ${project.version} + diff -r 6da66da9e8ac -r 6815308bb362 host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/HostCpuBackend.java --- a/host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/HostCpuBackend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/host-cpu/agent/src/main/java/com/redhat/thermostat/host/cpu/agent/internal/HostCpuBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -104,11 +104,6 @@ } @Override - protected void setDAOFactoryAction() { - // No use for DAOFactory - } - - @Override public String getConfigurationValue(String key) { return null; } diff -r 6da66da9e8ac -r 6815308bb362 host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/HostMemoryBackend.java --- a/host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/HostMemoryBackend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/host-memory/agent/src/main/java/com/redhat/thermostat/host/memory/agent/internal/HostMemoryBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -95,11 +95,6 @@ } @Override - protected void setDAOFactoryAction() { - // No use for DAOFactory - } - - @Override public String getConfigurationValue(String key) { return null; } diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/pom.xml Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,73 @@ + + + 4.0.0 + + thermostat-numa + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-numa-agent + bundle + Thermostat NUMA Agent plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + Red Hat, Inc. + com.redhat.thermostat.numa.agent + com.redhat.thermostat.numa.agent.internal.Activator + + com.redhat.thermostat.numa.agent + + + com.redhat.thermostat.numa.agent.internal + + + <_nouses>true + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-numa-common + ${project.version} + + + com.redhat.thermostat + thermostat-agent-core + ${project.version} + + + com.redhat.thermostat + thermostat-storage-core + ${project.version} + + + diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/Activator.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,99 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.agent.internal; + +import java.util.Map; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BackendService; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.numa.common.NumaDAO; + +public class Activator implements BundleActivator { + + private MultipleServiceTracker tracker; + private NumaBackend backend; + private ServiceRegistration reg; + + @Override + public void start(final BundleContext context) throws Exception { + + Class[] deps = new Class[] { + BackendService.class, NumaDAO.class, ApplicationService.class + }; + tracker = new MultipleServiceTracker(context, deps, new Action() { + + @Override + public void dependenciesAvailable(Map services) { + ApplicationService appService = (ApplicationService) services.get(ApplicationService.class.getName()); + NumaDAO numaDAO = (NumaDAO) services.get(NumaDAO.class.getName()); + Version version = new Version(context.getBundle()); + NumaCollector collector = new NumaCollector(); + backend = new NumaBackend(appService, numaDAO, collector, version); + reg = context.registerService(Backend.class.getName(), backend, null); + } + + @Override + public void dependenciesUnavailable() { + if (backend.isActive()) { + backend.deactivate(); + } + reg.unregister(); + } + }); + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + + /* + * For testing purposes only. + */ + NumaBackend getBackend() { + return backend; + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,130 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.agent.internal; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BackendID; +import com.redhat.thermostat.backend.BackendsProperties; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaStat; + +public class NumaBackend extends Backend { + + private static final Logger log = Logger.getLogger(NumaBackend.class.getName()); + + private static final long NUMA_CHECK_INTERVAL_SECONDS = 1; + + private NumaDAO numaDAO; + private ApplicationService appService; + private boolean started; + private NumaCollector numaCollector; + private Timer timer; + + public NumaBackend(ApplicationService appService, NumaDAO numaDAO, NumaCollector numaCollector, Version version) { + super(new BackendID("NUMA Backend", NumaBackend.class.getName())); + this.appService = appService; + this.numaDAO = numaDAO; + this.numaCollector = numaCollector; + + setConfigurationValue(BackendsProperties.VENDOR.name(), "Red Hat, Inc."); + setConfigurationValue(BackendsProperties.DESCRIPTION.name(), "Gathers NUMA statistics about a host"); + setConfigurationValue(BackendsProperties.VERSION.name(), version.getVersionNumber()); + + } + + @Override + public boolean activate() { + TimerFactory timerFactory = appService.getTimerFactory(); + timer = timerFactory.createTimer(); + timer.setDelay(NUMA_CHECK_INTERVAL_SECONDS); + timer.setInitialDelay(0); + timer.setSchedulingType(SchedulingType.FIXED_RATE); + timer.setTimeUnit(TimeUnit.SECONDS); + timer.setAction(new Runnable() { + + @Override + public void run() { + NumaStat[] stats; + try { + stats = numaCollector.collectData(); + for (NumaStat stat : stats) { + numaDAO.putNumaStat(stat); + } + } catch (IOException e) { + log.log(Level.WARNING, e.getMessage(), e); + } + } + }); + timer.start(); + started = true; + + return true; + } + + @Override + public boolean deactivate() { + started = false; + timer.stop(); + return true; + } + + @Override + public boolean isActive() { + return started; + } + + @Override + public boolean attachToNewProcessByDefault() { + return false; + } + + @Override + public int getOrderValue() { + return ORDER_CPU_GROUP; + } + +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.numa.agent.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; + +import com.redhat.thermostat.numa.common.NumaStat; + +class NumaCollector { + + private static final String NUMA_BASE_DIR = "/sys/devices/system/node"; + + private static final String NODE_DIR_PREFIX = "node"; + + private static final String NUMA_STAT_FILE = "numastat"; + + private int numberOfNodes; + + private File baseDir; + + NumaCollector() { + this(NUMA_BASE_DIR); + } + + NumaCollector(String baseDirectory) { + baseDir = new File(baseDirectory); + FilenameFilter filter = new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + return name.startsWith(NODE_DIR_PREFIX); + } + }; + String[] nodeFiles = baseDir.list(filter); + numberOfNodes = nodeFiles.length; + } + + NumaStat[] collectData() throws IOException { + NumaStat[] stat = new NumaStat[numberOfNodes]; + for (int i = 0; i < numberOfNodes; i++) { + File nodeDir = new File(baseDir, NODE_DIR_PREFIX + i); + File numaStatFile = new File(nodeDir, NUMA_STAT_FILE); + try (FileInputStream in = new FileInputStream(numaStatFile)) { + Reader reader = new InputStreamReader(in); + NumaStatBuilder builder = new NumaStatBuilder(reader); + stat[i] = builder.build(); + stat[i].setNode(i); + } + } + return stat; + } + + // This is here for testing. + String getBaseDir() { + return baseDir.getAbsolutePath(); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilder.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,82 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.agent.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +import com.redhat.thermostat.numa.common.NumaStat; + +class NumaStatBuilder { + + private Reader in; + + NumaStatBuilder(Reader in) { + this.in = in; + } + + NumaStat build() throws IOException { + NumaStat numaStat = new NumaStat(); + readNumaData(numaStat); + return numaStat; + } + + private void readNumaData(NumaStat numaStat) throws IOException { + BufferedReader bufIn = new BufferedReader(in); + String line = bufIn.readLine(); + while (line != null) { + String[] keyValue = line.split(" "); + String key = keyValue[0]; + long value = Long.parseLong(keyValue[1]); + if (key.equals("numa_hit")) { + numaStat.setNumaHit(value); + } else if (key.equals("numa_miss")) { + numaStat.setNumaMiss(value); + } else if (key.equals("numa_foreign")) { + numaStat.setNumaForeign(value); + } else if (key.equals("interleave_hit")) { + numaStat.setInterleaveHit(value); + } else if (key.equals("local_node")) { + numaStat.setLocalNode(value); + } else if (key.equals("other_node")) { + numaStat.setOtherNode(value); + } + line = bufIn.readLine(); + } + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/ActivatorTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,144 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.Version; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BackendService; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.test.StubBundleContext; + +public class ActivatorTest { + + private StubBundleContext context; + + private BackendService backendService; + private NumaDAO numaDAO; + private ApplicationService appService; + + @Before + public void setUp() { + context = new StubBundleContext() { + @Override + public Bundle getBundle() { + Bundle result = mock(Bundle.class); + when(result.getVersion()).thenReturn(Version.emptyVersion); + return result; + } + }; + + backendService = mock(BackendService.class); + numaDAO = mock(NumaDAO.class); + appService = mock(ApplicationService.class); + TimerFactory timerFactory = mock(TimerFactory.class); + Timer timer = mock(Timer.class); + when(timerFactory.createTimer()).thenReturn(timer); + when(appService.getTimerFactory()).thenReturn(timerFactory); + } + + @Test + public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { + StubBundleContext context = new StubBundleContext(); + + Activator activator = new Activator(); + + activator.start(context); + + assertEquals(0, context.getAllServices().size()); + assertEquals(3, context.getServiceListeners().size()); + + activator.stop(context); + } + + @Test + public void verifyActivatorRegistersServicesWithActivate() throws Exception { + + Activator activator = verifyActivatorRegistersServiceCommon(); + + NumaBackend backend = activator.getBackend(); + backend.activate(); + + verifyActivatorUnregistersServiceCommon(activator, backend); + } + + @Test + public void verifyActivatorRegistersServicesWithoutActivate() throws Exception { + + Activator activator = verifyActivatorRegistersServiceCommon(); + + NumaBackend backend = activator.getBackend(); + + verifyActivatorUnregistersServiceCommon(activator, backend); + } + + private Activator verifyActivatorRegistersServiceCommon() throws Exception { + context.registerService(BackendService.class, backendService, null); + context.registerService(NumaDAO.class, numaDAO, null); + context.registerService(ApplicationService.class, appService, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(Backend.class.getName(), NumaBackend.class)); + assertNotNull(activator.getBackend()); + return activator; + } + + private void verifyActivatorUnregistersServiceCommon(Activator activator, NumaBackend backend) throws Exception { + activator.stop(context); + + assertFalse(backend.isActive()); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(3, context.getAllServices().size()); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,149 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Ordered; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaStat; + +public class NumaBackendTest { + + private NumaBackend backend; + private ApplicationService appService; + private NumaDAO numaDAO; + private NumaCollector collector; + private Timer timer; + + @Before + public void setup() { + appService = mock(ApplicationService.class); + TimerFactory timerFactory = mock(TimerFactory.class); + timer = mock(Timer.class); + when(timerFactory.createTimer()).thenReturn(timer); + when(appService.getTimerFactory()).thenReturn(timerFactory); + collector = mock(NumaCollector.class); + Version version = mock(Version.class); + when(version.getVersionNumber()).thenReturn("0.0.0"); + numaDAO = mock(NumaDAO.class); + backend = new NumaBackend(appService, numaDAO, collector, version); + } + + @After + public void tearDown() { + backend = null; + collector = null; + timer = null; + appService = null; + numaDAO = null; + } + + @Test + public void testActivate() throws IOException { + ArgumentCaptor actionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(actionCaptor.capture()); + NumaStat stat1 = mock(NumaStat.class); + NumaStat stat2 = mock(NumaStat.class); + NumaStat[] stats = new NumaStat[] { stat1, stat2 }; + when(collector.collectData()).thenReturn(stats); + + boolean activated = backend.activate(); + assertTrue(activated); + assertTrue(backend.isActive()); + verify(timer).setDelay(1); + verify(timer).setInitialDelay(1); + verify(timer).setTimeUnit(TimeUnit.SECONDS); + verify(timer).setSchedulingType(Timer.SchedulingType.FIXED_RATE); + verify(timer).start(); + verify(timer).setAction(any(Runnable.class)); + verifyNoMoreInteractions(timer); + + Runnable action = actionCaptor.getValue(); + verifyZeroInteractions(numaDAO); + verifyZeroInteractions(collector); + + action.run(); + verify(collector).collectData(); + verify(numaDAO).putNumaStat(stat1); + verify(numaDAO).putNumaStat(stat2); + verifyNoMoreInteractions(numaDAO); + verifyNoMoreInteractions(collector); + + when(collector.collectData()).thenThrow(new IOException()); + action.run(); + verify(collector, times(2)).collectData(); + verifyNoMoreInteractions(collector); + verifyNoMoreInteractions(numaDAO); + + boolean deactivated = backend.deactivate(); + assertTrue(deactivated); + verify(timer).stop(); + } + + @Test + public void testAttachToNewProcessByDefault() { + assertFalse(backend.attachToNewProcessByDefault()); + } + + @Test + public void testOrderValue() { + assertEquals(Ordered.ORDER_CPU_GROUP, backend.getOrderValue()); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,166 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.numa.agent.internal; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.numa.common.NumaStat; + +public class NumaCollectorTest { + + private static final String TEST_STAT0 = "numa_hit 11\n" + + "numa_miss 12\n" + + "numa_foreign 13\n" + + "interleave_hit 14\n" + + "local_node 15\n" + + "other_node 16\n"; + + private static final String TEST_STAT1 = "numa_hit 21\n" + + "numa_miss 22\n" + + "numa_foreign 23\n" + + "interleave_hit 24\n" + + "local_node 25\n" + + "other_node 26\n"; + + private static final String TEST_STAT2 = "numa_hit 31\n" + + "numa_miss 32\n" + + "numa_foreign 33\n" + + "interleave_hit 34\n" + + "local_node 35\n" + + "other_node 36\n"; + + private File tmpDir; + + @Before + public void setUp() throws IOException { + tmpDir = Files.createTempDirectory("numa-test").toFile(); + + File nodeDir0 = new File(tmpDir, "node0"); + nodeDir0.mkdir(); + File numaStatFile0 = new File(nodeDir0, "numastat"); + FileOutputStream out0 = new FileOutputStream(numaStatFile0); + out0.write(TEST_STAT0.getBytes()); + out0.close(); + + File nodeDir1 = new File(tmpDir, "node1"); + nodeDir1.mkdir(); + File numaStatFile1 = new File(nodeDir1, "numastat"); + FileOutputStream out1 = new FileOutputStream(numaStatFile1); + out1.write(TEST_STAT1.getBytes()); + out1.close(); + + File nodeDir2 = new File(tmpDir, "node2"); + nodeDir2.mkdir(); + File numaStatFile2 = new File(nodeDir2, "numastat"); + FileOutputStream out2 = new FileOutputStream(numaStatFile2); + out2.write(TEST_STAT2.getBytes()); + out2.close(); + + File fluff = new File(tmpDir, "fluff"); + fluff.mkdir(); + + } + + @After + public void tearDown() throws IOException { + Files.walkFileTree(tmpDir.toPath(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return super.visitFile(file, attrs); + } + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return super.postVisitDirectory(dir, exc); + } + }); + } + + @Test + public void testStats() throws IOException { + NumaCollector coll = new NumaCollector(tmpDir.getAbsolutePath()); + NumaStat[] stats = coll.collectData(); + + assertEquals(3, stats.length); + + assertEquals(0, stats[0].getNode()); + assertEquals(11, stats[0].getNumaHit()); + assertEquals(12, stats[0].getNumaMiss()); + assertEquals(13, stats[0].getNumaForeign()); + assertEquals(14, stats[0].getInterleaveHit()); + assertEquals(15, stats[0].getLocalNode()); + assertEquals(16, stats[0].getOtherNode()); + + assertEquals(1, stats[1].getNode()); + assertEquals(21, stats[1].getNumaHit()); + assertEquals(22, stats[1].getNumaMiss()); + assertEquals(23, stats[1].getNumaForeign()); + assertEquals(24, stats[1].getInterleaveHit()); + assertEquals(25, stats[1].getLocalNode()); + assertEquals(26, stats[1].getOtherNode()); + + assertEquals(2, stats[2].getNode()); + assertEquals(31, stats[2].getNumaHit()); + assertEquals(32, stats[2].getNumaMiss()); + assertEquals(33, stats[2].getNumaForeign()); + assertEquals(34, stats[2].getInterleaveHit()); + assertEquals(35, stats[2].getLocalNode()); + assertEquals(36, stats[2].getOtherNode()); + + } + + @Test + public void testDefaultDir() { + NumaCollector coll = new NumaCollector(); + assertEquals("/sys/devices/system/node", coll.getBaseDir()); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilderTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,71 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.agent.internal; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; + +import org.junit.Test; + +import com.redhat.thermostat.numa.common.NumaStat; + +public class NumaStatBuilderTest { + + private static final String TEST_STAT = "numa_hit 32931\n" + + "numa_miss 819\n" + + "numa_foreign 918\n" + + "interleave_hit 5704\n" + + "local_node 3293\n" + + "other_node 1819\n"; + + @Test + public void test() throws IOException { + Reader in = new StringReader(TEST_STAT); + NumaStatBuilder builder = new NumaStatBuilder(in); + NumaStat stat = builder.build(); + assertEquals(32931L, stat.getNumaHit()); + assertEquals(819L, stat.getNumaMiss()); + assertEquals(918L, stat.getNumaForeign()); + assertEquals(5704L, stat.getInterleaveHit()); + assertEquals(3293L, stat.getLocalNode()); + assertEquals(1819L, stat.getOtherNode()); + } + +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/pom.xml Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,68 @@ + + + 4.0.0 + + thermostat-numa + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-numa-common + bundle + Thermostat NUMA Common plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + Red Hat, Inc. + com.redhat.thermostat.numa.common + com.redhat.thermostat.numa.common.internal.Activator + + com.redhat.thermostat.numa.common + + + com.redhat.thermostat.numa.common.internal + + + <_nouses>true + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-storage-core + ${project.version} + + + diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.common; + +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; + +public interface NumaDAO { + + static final Key nodeKey = new Key<>("node", true); + static final Key numaHitKey = new Key<>("numaHit", false); + static final Key numaMissKey = new Key<>("numaMiss", false); + static final Key numaForeignKey = new Key<>("numaForeign", false); + static final Key interleaveHitKey = new Key<>("interleaveHit", false); + static final Key localNodeKey = new Key<>("localNode", false); + static final Key otherNodeKey = new Key<>("otherNode", false); + + static final Category numaStatCategory = new Category<>("numa-stat", NumaStat.class, Key.AGENT_ID, Key.TIMESTAMP, + nodeKey, numaHitKey, numaMissKey, numaForeignKey, interleaveHitKey, localNodeKey, otherNodeKey); + + void putNumaStat(NumaStat stat); +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,110 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.common; + +import com.redhat.thermostat.storage.model.BasePojo; + +public class NumaStat extends BasePojo { + + private long numaHit = -1; + private long numaMiss = -1; + private long numaForeign = -1; + private long interleaveHit = -1; + private long localNode = -1; + private long otherNode = -1; + private int node = -1; + + public long getNumaHit() { + return numaHit; + } + + public void setNumaHit(long numaHit) { + this.numaHit = numaHit; + } + + public long getNumaMiss() { + return numaMiss; + } + + public void setNumaMiss(long numaMiss) { + this.numaMiss = numaMiss; + } + + public long getNumaForeign() { + return numaForeign; + } + + public void setNumaForeign(long numaForeign) { + this.numaForeign = numaForeign; + } + + public long getInterleaveHit() { + return interleaveHit; + } + + public void setInterleaveHit(long interleaveHit) { + this.interleaveHit = interleaveHit; + } + + public long getLocalNode() { + return localNode; + } + + public void setLocalNode(long localNode) { + this.localNode = localNode; + } + + public long getOtherNode() { + return otherNode; + } + + public void setOtherNode(long otherNode) { + this.otherNode = otherNode; + } + + public int getNode() { + return node; + } + + public void setNode(int node) { + this.node = node; + } + + public String toString() { + return "NumaStat: node: " + node + ", numaHit: " + numaHit + ", numaMiss: " + numaMiss + ", numaForeign: " + numaForeign + ", interleaveHit: " + interleaveHit + ", localNode: " + localNode + ", otherNode: " + otherNode; + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/Activator.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,79 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.common.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.storage.core.Storage; + +public class Activator implements BundleActivator { + + private ServiceTracker tracker; + private ServiceRegistration reg; + + @Override + public void start(BundleContext context) throws Exception { + tracker = new ServiceTracker(context, Storage.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + Storage storage = (Storage) context.getService(reference); + NumaDAO memoryStatDao = new NumaDAOImpl(storage); + reg = context.registerService(NumaDAO.class.getName(), memoryStatDao, null); + return super.addingService(reference); + } + + @Override + public void removedService(ServiceReference reference, + Object service) { + reg.unregister(); + super.removedService(reference, service); + } + }; + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.common.internal; + +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaStat; +import com.redhat.thermostat.storage.core.Put; +import com.redhat.thermostat.storage.core.Storage; + +public class NumaDAOImpl implements NumaDAO { + + private final Storage storage; + + NumaDAOImpl(Storage storage) { + this.storage = storage; + storage.registerCategory(numaStatCategory); + } + + @Override + public void putNumaStat(NumaStat stat) { + Put add = storage.createAdd(numaStatCategory); + add.setPojo(stat); + add.apply(); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaDAOTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaDAOTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,78 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.numa.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Category; + +public class NumaDAOTest { + + @Test + public void testCategory() { + Category cat = NumaDAO.numaStatCategory; + assertEquals("numa-stat", cat.getName()); + assertEquals(NumaStat.class, cat.getDataClass()); + assertEquals(9, cat.getKeys().size()); + + assertEquals("agentId", cat.getKey("agentId").getName()); + assertTrue(cat.getKey("agentId").isPartialCategoryKey()); + assertEquals("timeStamp", cat.getKey("timeStamp").getName()); + assertFalse(cat.getKey("timeStamp").isPartialCategoryKey()); + + assertEquals("node", cat.getKey("node").getName()); + assertTrue(cat.getKey("node").isPartialCategoryKey()); + + assertEquals("numaHit", cat.getKey("numaHit").getName()); + assertFalse(cat.getKey("numaHit").isPartialCategoryKey()); + assertEquals("numaMiss", cat.getKey("numaMiss").getName()); + assertFalse(cat.getKey("numaMiss").isPartialCategoryKey()); + assertEquals("numaForeign", cat.getKey("numaForeign").getName()); + assertFalse(cat.getKey("numaForeign").isPartialCategoryKey()); + assertEquals("interleaveHit", cat.getKey("interleaveHit").getName()); + assertFalse(cat.getKey("interleaveHit").isPartialCategoryKey()); + assertEquals("localNode", cat.getKey("localNode").getName()); + assertFalse(cat.getKey("localNode").isPartialCategoryKey()); + assertEquals("otherNode", cat.getKey("otherNode").getName()); + assertFalse(cat.getKey("otherNode").isPartialCategoryKey()); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaStatTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaStatTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.numa.common; + +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class NumaStatTest { + + private NumaStat stat; + + @Before + public void setUp() { + stat = new NumaStat(); + stat.setNode(1); + stat.setNumaHit(2); + stat.setNumaMiss(3); + stat.setNumaForeign(4); + stat.setInterleaveHit(5); + stat.setLocalNode(6); + stat.setOtherNode(7); + } + + @After + public void tearDown() { + stat = null; + } + + @Test + public void testDefaults() { + NumaStat stat = new NumaStat(); + assertEquals(-1, stat.getNode()); + assertEquals(-1, stat.getNumaHit()); + assertEquals(-1, stat.getNumaMiss()); + assertEquals(-1, stat.getNumaForeign()); + assertEquals(-1, stat.getInterleaveHit()); + assertEquals(-1, stat.getLocalNode()); + assertEquals(-1, stat.getOtherNode()); + } + + @Test + public void testProperties() { + + assertEquals(1, stat.getNode()); + assertEquals(2, stat.getNumaHit()); + assertEquals(3, stat.getNumaMiss()); + assertEquals(4, stat.getNumaForeign()); + assertEquals(5, stat.getInterleaveHit()); + assertEquals(6, stat.getLocalNode()); + assertEquals(7, stat.getOtherNode()); + + } + + @Test + public void testToString() { + NumaStat stat = new NumaStat(); + stat.setNode(1); + stat.setNumaHit(2); + stat.setNumaMiss(3); + stat.setNumaForeign(4); + stat.setInterleaveHit(5); + stat.setLocalNode(6); + stat.setOtherNode(7); + + String str = stat.toString(); + String expected = "NumaStat: node: 1, numaHit: 2, numaMiss: 3, numaForeign: 4, interleaveHit: 5, localNode: 6, otherNode: 7"; + assertEquals(expected, str); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/ActivatorTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,86 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.numa.common.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.internal.Activator; +import com.redhat.thermostat.numa.common.internal.NumaDAOImpl; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.test.StubBundleContext; + +public class ActivatorTest { + + @Test + public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { + StubBundleContext context = new StubBundleContext(); + + Activator activator = new Activator(); + + activator.start(context); + + assertEquals(0, context.getAllServices().size()); + assertEquals(1, context.getServiceListeners().size()); + + activator.stop(context); + } + + @Test + public void verifyActivatorRegistersServices() throws Exception { + StubBundleContext context = new StubBundleContext(); + Storage storage = mock(Storage.class); + + context.registerService(Storage.class, storage, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(NumaDAO.class.getName(), NumaDAOImpl.class)); + + activator.stop(context); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(1, context.getAllServices().size()); + } + +} diff -r 6da66da9e8ac -r 6815308bb362 numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,100 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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 2, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + + +package com.redhat.thermostat.numa.common.internal; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaStat; +import com.redhat.thermostat.storage.core.Add; +import com.redhat.thermostat.storage.core.Storage; + +public class NumaDAOImplTest { + + private NumaDAO numaDAO; + private Storage storage; + + @Before + public void setUp() { + storage = mock(Storage.class); + numaDAO = new NumaDAOImpl(storage); + } + + @After + public void tearDown() { + numaDAO = null; + storage = null; + } + + @Test + public void testRegisterCategory() { + verify(storage).registerCategory(NumaDAO.numaStatCategory); + } + + @Test + public void testPutNumaStat() { + + Add add = mock(Add.class); + when(storage.createAdd(NumaDAO.numaStatCategory)).thenReturn(add); + + NumaStat stat = new NumaStat(); + stat.setNode(1); + stat.setNumaHit(2); + stat.setNumaMiss(3); + stat.setNumaForeign(4); + stat.setInterleaveHit(5); + stat.setLocalNode(6); + stat.setOtherNode(7); + + numaDAO.putNumaStat(stat); + + verify(storage).registerCategory(NumaDAO.numaStatCategory); + verify(storage).createAdd(NumaDAO.numaStatCategory); + verifyNoMoreInteractions(storage); + verify(add).setPojo(stat); + verify(add).apply(); + verifyNoMoreInteractions(add); + } +} diff -r 6da66da9e8ac -r 6815308bb362 numa/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/pom.xml Tue Jan 15 23:00:52 2013 +0100 @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + com.redhat.thermostat + thermostat + 0.5.0-SNAPSHOT + + + thermostat-numa + pom + + Thermostat NUMA plugin + + + agent + common + + + diff -r 6da66da9e8ac -r 6815308bb362 pom.xml --- a/pom.xml Thu Jan 10 21:48:04 2013 +0100 +++ b/pom.xml Tue Jan 15 23:00:52 2013 +0100 @@ -140,6 +140,7 @@ vm-classstat vm-memory vm-heap-analysis + numa dev diff -r 6da66da9e8ac -r 6815308bb362 vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java --- a/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/vm-classstat/agent/src/main/java/com/redhat/thermostat/vm/classstat/agent/internal/VmClassStatBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -113,11 +113,6 @@ } @Override - protected void setDAOFactoryAction() { - // No need for DAOFactory - } - - @Override public String getConfigurationValue(String key) { return null; } diff -r 6da66da9e8ac -r 6815308bb362 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java --- a/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -151,11 +151,6 @@ } @Override - protected void setDAOFactoryAction() { - // No need for DAOFactory - } - - @Override public String getConfigurationValue(String key) { return null; } diff -r 6da66da9e8ac -r 6815308bb362 vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java --- a/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -110,11 +110,6 @@ public boolean isActive() { return started; } - - @Override - protected void setDAOFactoryAction() { - // No need for DAOFactory - } @Override public String getConfigurationValue(String key) { diff -r 6da66da9e8ac -r 6815308bb362 vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java --- a/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java Thu Jan 10 21:48:04 2013 +0100 +++ b/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java Tue Jan 15 23:00:52 2013 +0100 @@ -110,11 +110,6 @@ public boolean isActive() { return started; } - - @Override - protected void setDAOFactoryAction() { - // No need for DAOFactory - } @Override public String getConfigurationValue(String key) {