Mercurial > hg > release > thermostat-1.2
changeset 1556:247db2fa05c5
Allow cli client to get profiling results
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-November/011523.html
line wrap: on
line diff
--- a/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/Activator.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/Activator.java Tue Nov 18 14:07:31 2014 -0500 @@ -46,6 +46,8 @@ import com.redhat.thermostat.agent.command.ReceiverRegistry; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.storage.core.WriterID; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; public class Activator implements BundleActivator { @@ -56,7 +58,11 @@ final Properties configuration = new Properties(); configuration.load(this.getClass().getResourceAsStream("settings.properties")); - Class<?>[] deps = new Class<?>[] { MXBeanConnectionPool.class }; + Class<?>[] deps = new Class<?>[] { + MXBeanConnectionPool.class, + ProfileDAO.class, + WriterID.class, + }; tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() { private ReceiverRegistry requestHandlerRegisteration; private VmStatusListenerRegistrar vmStatusRegistrar; @@ -74,9 +80,13 @@ @Override public void dependenciesAvailable(Map<String, Object> services) { - MXBeanConnectionPool pool = (MXBeanConnectionPool) services.get(MXBeanConnectionPool.class.getName()); + MXBeanConnectionPool pool = get(MXBeanConnectionPool.class, services); + WriterID writerIdProvider = get(WriterID.class, services); + ProfileDAO dao = get(ProfileDAO.class, services); + String writerId = writerIdProvider.getWriterID(); + VmProfiler profiler = new VmProfiler(configuration, pool); - profileRequestHandler = new ProfileVmRequestReceiver(profiler); + profileRequestHandler = new ProfileVmRequestReceiver(writerId, profiler, dao); requestHandlerRegisteration = new ReceiverRegistry(context); requestHandlerRegisteration.registerReceiver(profileRequestHandler); @@ -84,6 +94,9 @@ vmStatusRegistrar = new VmStatusListenerRegistrar(context); vmStatusRegistrar.register(profileRequestHandler); } + private <T> T get(Class<T> klass, Map<String, Object> services) { + return (T) services.get(klass.getName()); + } }); tracker.open();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/ProfileUploader.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.agent.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; + +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileInfo; + +public class ProfileUploader { + + private final ProfileDAO dao; + private final String agentId; + private final String vmId; + + public ProfileUploader(ProfileDAO dao, String agentId, String vmId, int pid) { + this.dao = dao; + this.agentId = agentId; + this.vmId = vmId; + } + + public void upload(long timeStamp, File data) throws IOException { + // FIXME resource leak: file is never closed + upload(timeStamp, new FileInputStream(data)); + } + + public void upload(long timeStamp, InputStream data) throws IOException { + String id = UUID.randomUUID().toString(); + ProfileInfo info = new ProfileInfo(agentId, vmId, timeStamp, id); + dao.saveProfileData(info, data); + } +}
--- a/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/ProfileVmRequestReceiver.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/ProfileVmRequestReceiver.java Tue Nov 18 14:07:31 2014 -0500 @@ -46,6 +46,7 @@ import com.redhat.thermostat.common.command.Response; import com.redhat.thermostat.common.command.Response.ResponseType; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; import com.redhat.thermostat.vm.profiler.common.ProfileRequest; public class ProfileVmRequestReceiver implements RequestReceiver, VmStatusListener { @@ -57,10 +58,16 @@ /** A pid that corresponds to an unknown */ private static final int UNKNOWN_VMID = -1; + private final String agentId; + private final VmProfiler profiler; + private final ProfileDAO dao; - public ProfileVmRequestReceiver(VmProfiler profiler) { + public ProfileVmRequestReceiver(String agentId, VmProfiler profiler, ProfileDAO dao) { this.profiler = profiler; + this.dao = dao; + + this.agentId = agentId; } @Override @@ -102,7 +109,8 @@ case ProfileRequest.STOP_PROFILING: logger.info("Stopping profiling " + pid); try { - profiler.stopProfiling(pid); + ProfileUploader uploader = new ProfileUploader(dao, agentId, vmId, pid); + profiler.stopProfiling(pid, uploader); return OK; } catch (Exception e) { logger.log(Level.INFO, "stop profiling failed", e);
--- a/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/VmProfiler.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/internal/VmProfiler.java Tue Nov 18 14:07:31 2014 -0500 @@ -36,6 +36,7 @@ package com.redhat.thermostat.vm.profiler.agent.internal; +import java.io.File; import java.io.IOException; import java.util.Objects; import java.util.Properties; @@ -46,6 +47,8 @@ import com.redhat.thermostat.agent.utils.management.MXBeanConnection; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.common.SystemClock; import com.redhat.thermostat.common.utils.LoggingUtils; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.AgentLoadException; @@ -58,17 +61,19 @@ private final MXBeanConnectionPool connectionPool; private final Attacher attacher; + private final Clock clock; private String agentJarPath; private String asmJarPath; public VmProfiler(Properties configuration, MXBeanConnectionPool connectionPool) { - this(configuration, connectionPool, new Attacher()); + this(configuration, connectionPool, new Attacher(), new SystemClock()); } - public VmProfiler(Properties configuration, MXBeanConnectionPool connectionPool, Attacher attacher) { + public VmProfiler(Properties configuration, MXBeanConnectionPool connectionPool, Attacher attacher, Clock clock) { this.connectionPool = connectionPool; this.attacher = attacher; + this.clock = clock; // requireNonNull protects against bad config with missing values agentJarPath = Objects.requireNonNull(configuration.getProperty("AGENT_JAR")); @@ -98,22 +103,44 @@ } } - public void stopProfiling(int pid) throws ProfilerException { + public void stopProfiling(int pid, ProfileUploader uploader) throws ProfilerException { invokeMethodOnInstrumentation(pid, "stopProfiling"); + + String profilingDataFile = (String) getInstrumentationAttribute(pid, "ProfilingDataFile"); + try { + uploader.upload(clock.getRealTimeMillis(), new File(profilingDataFile)); + } catch (IOException e) { + throw new ProfilerException("Unable to save profiling data into storage", e); + } } - private void invokeMethodOnInstrumentation(int pid, String name) throws ProfilerException { + private Object invokeMethodOnInstrumentation(int pid, String name) throws ProfilerException { try { MXBeanConnection connection = connectionPool.acquire(pid); try { ObjectName instrumentation = new ObjectName("com.redhat.thermostat:type=InstrumentationControl"); MBeanServerConnection server = connection.get(); - server.invoke(instrumentation, name, new Object[0], new String[0]); + return server.invoke(instrumentation, name, new Object[0], new String[0]); } finally { connectionPool.release(pid, connection); } } catch (Exception e) { - throw new ProfilerException("Unable to start remote profiling", e); + throw new ProfilerException("Unable to communicate with remote profiler", e); + } + } + + private Object getInstrumentationAttribute(int pid, String name) throws ProfilerException { + try { + MXBeanConnection connection = connectionPool.acquire(pid); + try { + ObjectName instrumentation = new ObjectName("com.redhat.thermostat:type=InstrumentationControl"); + MBeanServerConnection server = connection.get(); + return server.getAttribute(instrumentation, name); + } finally { + connectionPool.release(pid, connection); + } + } catch (Exception e) { + throw new ProfilerException("Unable to communicate with remote profiler", e); } }
--- a/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/ActivatorTest.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/ActivatorTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -44,15 +44,22 @@ import com.redhat.thermostat.agent.command.RequestReceiver; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.testutils.StubBundleContext; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; public class ActivatorTest { @Test public void requestHandlerIsRegistered() throws Exception { MXBeanConnectionPool pool = mock(MXBeanConnectionPool.class); + WriterID writerService = mock(WriterID.class); + ProfileDAO dao = mock(ProfileDAO.class); + StubBundleContext context = new StubBundleContext(); context.registerService(MXBeanConnectionPool.class, pool, null); + context.registerService(ProfileDAO.class, dao, null); + context.registerService(WriterID.class, writerService, null); Activator activator = new Activator();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/ProfileUploaderTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileInfo; + +public class ProfileUploaderTest { + + private ProfileDAO dao; + + private final String AGENT_ID = "agent-id"; + private final String VM_ID = "vm-id"; + private final int PID = -1; + private final long TIME = 1_000_000_000; + + private ProfileUploader uploader; + + @Before + public void setUp() { + dao = mock(ProfileDAO.class); + + uploader = new ProfileUploader(dao, AGENT_ID, VM_ID, PID); + } + + @Test + public void uploadFile() throws Exception { + byte[] data = "Test Profile Data".getBytes(StandardCharsets.UTF_8); + ByteArrayInputStream input = new ByteArrayInputStream(data); + + ArgumentCaptor<ProfileInfo> profileInfoCaptor = ArgumentCaptor.forClass(ProfileInfo.class); + + uploader.upload(TIME, input); + + verify(dao).saveProfileData(profileInfoCaptor.capture(), eq(input)); + ProfileInfo profileInfo = profileInfoCaptor.getValue(); + assertEquals(AGENT_ID, profileInfo.getAgentId()); + assertEquals(VM_ID, profileInfo.getVmId()); + assertEquals(TIME, profileInfo.getTimeStamp()); + assertNotNull(profileInfo.getProfileId()); + } +}
--- a/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/ProfileVmRequestReceiverTest.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/ProfileVmRequestReceiverTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -37,6 +37,8 @@ package com.redhat.thermostat.vm.profiler.agent.internal; import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -47,22 +49,28 @@ import com.redhat.thermostat.common.command.Request; import com.redhat.thermostat.common.command.Response; import com.redhat.thermostat.common.command.Response.ResponseType; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; import com.redhat.thermostat.vm.profiler.common.ProfileRequest; public class ProfileVmRequestReceiverTest { + private static final String AGENT_ID = "agent-id"; + private static final String VM_ID = "foo"; private static final int VM_PID = 1; private ProfileVmRequestReceiver requestReceiver; private VmProfiler profiler; + private ProfileDAO dao; + private ProfileUploader uploader; @Before public void setUp() { profiler = mock(VmProfiler.class); + dao = mock(ProfileDAO.class); - requestReceiver = new ProfileVmRequestReceiver(profiler); + requestReceiver = new ProfileVmRequestReceiver(AGENT_ID, profiler, dao); } @Test @@ -98,7 +106,7 @@ result = requestReceiver.receive(request); assertEquals(ResponseType.OK, result.getType()); - verify(profiler).stopProfiling(VM_PID); + verify(profiler).stopProfiling(eq(VM_PID), isA(ProfileUploader.class)); } @Test
--- a/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/VmProfilerTest.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/agent/src/test/java/com/redhat/thermostat/vm/profiler/agent/internal/VmProfilerTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -38,10 +38,12 @@ import static org.mockito.Matchers.isA; 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.when; +import java.io.File; import java.util.Properties; import javax.management.MBeanServerConnection; @@ -52,6 +54,7 @@ import com.redhat.thermostat.agent.utils.management.MXBeanConnection; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.common.Clock; import com.redhat.thermostat.vm.profiler.agent.internal.VmProfiler.Attacher; import com.sun.tools.attach.VirtualMachine; @@ -64,11 +67,13 @@ private MXBeanConnection connection; private MXBeanConnectionPool connectionPool; private Attacher attacher; + private Clock clock; private final int PID = 0; private final String AGENT_JAR = "foo"; private final String ASM_JAR = "bar"; + private final long TIME = 1_000_000_000; private ObjectName instrumentationName; @@ -80,6 +85,9 @@ props.setProperty("AGENT_JAR", AGENT_JAR); props.setProperty("ASM_JAR", ASM_JAR); + clock = mock(Clock.class); + when(clock.getRealTimeMillis()).thenReturn(TIME); + attacher = mock(Attacher.class); vm = mock(VirtualMachine.class); when(attacher.attach(isA(String.class))).thenReturn(vm); @@ -92,7 +100,7 @@ connectionPool = mock(MXBeanConnectionPool.class); when(connectionPool.acquire(PID)).thenReturn(connection); - profiler = new VmProfiler(props, connectionPool, attacher); + profiler = new VmProfiler(props, connectionPool, attacher, clock); } @Test @@ -110,11 +118,19 @@ @Test public void stoppingProfilingLoadsJvmAgentAndMakesAnRmiCall() throws Exception { - profiler.stopProfiling(PID); + final String FILE = "foobar"; + when(server.getAttribute(instrumentationName, "ProfilingDataFile")).thenReturn(FILE); + + ProfileUploader uploader = mock(ProfileUploader.class); + + profiler.stopProfiling(PID, uploader); verifyNoMoreInteractions(vm); verify(server).invoke(instrumentationName, "stopProfiling", new Object[0], new String[0]); - verify(connectionPool).release(PID, connection); + verify(uploader).upload(TIME, new File(FILE)); + verify(connectionPool, times(2)).release(PID, connection); + + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/AbstractCommand.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,88 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.client.cli.internal; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public abstract class AbstractCommand extends com.redhat.thermostat.common.cli.AbstractCommand { + + // TODO these changes should probably be promoted to the AbstractCommand public API + + protected Map<Class<?>, BlockingQueue<?>> serviceHolder = new HashMap<>(); + + private <T> BlockingQueue<T> getHolder(Class<T> serviceClass) { + if (!serviceHolder.containsKey(serviceClass)) { + serviceHolder.put(serviceClass, new LinkedBlockingQueue<T>(1)); + } + return (BlockingQueue<T>) serviceHolder.get(serviceClass); + } + + /** Insert {@code item} if it's non-{@code null} otherwise remove it */ + protected <T> void addOrRemoveService(Class<T> serviceClass, T item) { + BlockingQueue<T> holder = getHolder(serviceClass); + if (item == null) { + if (holder.peek() != null) { + holder.remove(); + } + } else { + try { + holder.put(item); + } catch (InterruptedException e) { + throw new AssertionError("Should not happen"); + } + } + } + + protected <T> T getService(Class<T> serviceClass) { + BlockingQueue<T> holder = getHolder(serviceClass); + try { + // a crappy version of peek()-with-timeout + T retValue = holder.poll(500, TimeUnit.MILLISECONDS); + if (retValue != null) { + holder.add(retValue); + } + return retValue; + } catch (InterruptedException e) { + return null; + } + } + +}
--- a/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/Activator.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/Activator.java Tue Nov 18 14:07:31 2014 -0500 @@ -49,26 +49,32 @@ import com.redhat.thermostat.common.cli.Command; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; public class Activator implements BundleActivator { - private MultipleServiceTracker profileCommandDepsTracker; - private ServiceRegistration<Command> registration; + private MultipleServiceTracker profileVmCommandDepsTracker; + private ServiceRegistration<Command> profileVmCommandRegistration; @Override public void start(final BundleContext context) throws Exception { + registerProfileVmCommand(context); + } + + private void registerProfileVmCommand(final BundleContext context) { final ProfileVmCommand command = new ProfileVmCommand(); Hashtable<String,? super Object> properties = new Hashtable<>(); properties.put(Command.NAME, "profile-vm"); - registration = context.registerService(Command.class, command, properties); + profileVmCommandRegistration = context.registerService(Command.class, command, properties); Class<?>[] classes = new Class<?>[] { AgentInfoDAO.class, VmInfoDAO.class, RequestQueue.class, + ProfileDAO.class, }; - profileCommandDepsTracker = new MultipleServiceTracker(context, classes, new Action() { + profileVmCommandDepsTracker = new MultipleServiceTracker(context, classes, new Action() { @Override public void dependenciesAvailable(Map<String, Object> services) { AgentInfoDAO agentInfoDao = (AgentInfoDAO) services.get(AgentInfoDAO.class.getName()); @@ -77,6 +83,8 @@ command.setVmInfoDAO(vmInfoDao); RequestQueue requestQueue = (RequestQueue) services.get(RequestQueue.class.getName()); command.setRequestQueue(requestQueue); + ProfileDAO profileDao = (ProfileDAO) services.get(ProfileDAO.class.getName()); + command.setProfileDAO(profileDao); } @Override @@ -87,15 +95,16 @@ } }); - profileCommandDepsTracker.open(); + profileVmCommandDepsTracker.open(); } @Override public void stop(BundleContext context) throws Exception { - profileCommandDepsTracker.close(); - profileCommandDepsTracker = null; + profileVmCommandDepsTracker.close(); + profileVmCommandDepsTracker = null; - registration.unregister(); + profileVmCommandRegistration.unregister(); + profileVmCommandRegistration = null; } }
--- a/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/ProfileVmCommand.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/client-cli/src/main/java/com/redhat/thermostat/vm/profiler/client/cli/internal/ProfileVmCommand.java Tue Nov 18 14:07:31 2014 -0500 @@ -36,16 +36,16 @@ package com.redhat.thermostat.vm.profiler.client.cli.internal; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.net.InetSocketAddress; import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; import com.redhat.thermostat.client.cli.HostVMArguments; import com.redhat.thermostat.client.command.RequestQueue; -import com.redhat.thermostat.common.cli.AbstractCommand; import com.redhat.thermostat.common.cli.CommandContext; import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.cli.Console; @@ -53,10 +53,13 @@ import com.redhat.thermostat.common.command.RequestResponseListener; import com.redhat.thermostat.common.command.Response; import com.redhat.thermostat.common.command.Response.ResponseType; +import com.redhat.thermostat.common.utils.StreamUtils; import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.VmInfoDAO; import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; import com.redhat.thermostat.vm.profiler.common.ProfileRequest; public class ProfileVmCommand extends AbstractCommand { @@ -65,23 +68,20 @@ private static final String START_ARGUMENT = "start"; private static final String STOP_ARGUMENT = "stop"; - - private final BlockingQueue<VmInfoDAO> vmInfoDAOHolder = new LinkedBlockingQueue<>(1); - private final BlockingQueue<AgentInfoDAO> agentInfoDAOHolder = new LinkedBlockingQueue<>(1); - private final BlockingQueue<RequestQueue> requestQueueHolder = new LinkedBlockingQueue<>(1); + private static final String SHOW_ARGUMENT = "show"; @Override public void run(CommandContext ctx) throws CommandException { HostVMArguments args = new HostVMArguments(ctx.getArguments(), true, true); - AgentInfoDAO agentInfoDAO = getFromHolder(agentInfoDAOHolder); - VmInfoDAO vmInfoDAO = getFromHolder(vmInfoDAOHolder); + AgentInfoDAO agentInfoDAO = getService(AgentInfoDAO.class); + VmInfoDAO vmInfoDAO = getService(VmInfoDAO.class); requireNonNull(agentInfoDAO, translator.localize(LocaleResources.AGENT_SERVICE_UNAVAILABLE)); requireNonNull(vmInfoDAO, translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE)); - RequestQueue requestQueue = getFromHolder(requestQueueHolder); + RequestQueue requestQueue = getService(RequestQueue.class); requireNonNull(requestQueue, translator.localize(LocaleResources.QUEUE_SERVICE_UNAVAILABLE)); AgentInformation agentInfo = agentInfoDAO.getAgentInformation(args.getHost()); @@ -106,6 +106,9 @@ case STOP_ARGUMENT: sendStopProfilingRequest(ctx.getConsole(), requestQueue, target, args.getVM().getVmId()); break; + case SHOW_ARGUMENT: + showProfilingResults(ctx.getConsole(), args.getVM()); + break; default: throw new CommandException(translator.localize(LocaleResources.UNKNOWN_COMMAND, command)); } @@ -166,41 +169,34 @@ } - /** Insert {@code item} if it's non-{@code null} otherwise remove it */ - private static <T> void addOrRemoveFromHoler(BlockingQueue<T> holder, T item) { - if (item == null) { - if (holder.peek() != null) { - holder.remove(); - } - } else { - try { - holder.put(item); - } catch (InterruptedException e) { - throw new AssertionError("Should not happen"); - } - } + private void showProfilingResults(Console console, VmRef vm) { + ProfileDAO dao = getService(ProfileDAO.class); + InputStream data = dao.loadLatestProfileData(vm); + displayProfilingData(console, data); } - private static <T> T getFromHolder(BlockingQueue<T> holder) { + private void displayProfilingData(Console console, InputStream data) { try { - // a crappy version of peek()-with-timeout - T retValue = holder.poll(500, TimeUnit.MILLISECONDS); - holder.add(retValue); - return retValue; - } catch (InterruptedException e) { - return null; + StreamUtils.copyStream(new BufferedInputStream(data), new BufferedOutputStream(console.getOutput())); + } catch (IOException e) { + console.getError().println("Error displaying data"); + e.printStackTrace(); } } void setAgentInfoDAO(AgentInfoDAO dao) { - addOrRemoveFromHoler(agentInfoDAOHolder, dao); + addOrRemoveService(AgentInfoDAO.class, dao); } void setVmInfoDAO(VmInfoDAO dao) { - addOrRemoveFromHoler(vmInfoDAOHolder, dao); + addOrRemoveService(VmInfoDAO.class, dao); } void setRequestQueue(RequestQueue queue) { - addOrRemoveFromHoler(requestQueueHolder, queue); + addOrRemoveService(RequestQueue.class, queue); + } + + void setProfileDAO(ProfileDAO dao) { + addOrRemoveService(ProfileDAO.class, dao); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/ProfileDAO.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common; + +import java.io.InputStream; + +import com.redhat.thermostat.annotations.Service; +import com.redhat.thermostat.storage.core.VmRef; + +@Service +public interface ProfileDAO { + + void saveProfileData(ProfileInfo info, InputStream data); + + /** @return {@code null} if no data is available */ + InputStream loadLatestProfileData(VmRef vm); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/ProfileInfo.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common; + +import com.redhat.thermostat.storage.core.Entity; +import com.redhat.thermostat.storage.core.Persist; +import com.redhat.thermostat.storage.model.BasePojo; +import com.redhat.thermostat.storage.model.TimeStampedPojo; + +@Entity +public class ProfileInfo extends BasePojo implements TimeStampedPojo { + + private String vmId; + + // FIXME should be two fields for start time and stop time + private long timeStamp; + + private String profileId; + + public ProfileInfo(String agentId, String vmId, long timeStamp, String profileId) { + super(agentId); + this.vmId = vmId; + this.timeStamp = timeStamp; + this.profileId = profileId; + } + + /* for deserialization */ + public ProfileInfo() { + super(null); // fixed up by the deserializer + } + + @Persist + public void setVmId(String vmId) { + this.vmId = vmId; + } + + @Persist + public String getVmId() { + return this.vmId; + } + + @Persist + public void setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + } + + @Persist + @Override + public long getTimeStamp() { + return this.timeStamp; + } + + @Persist + public String getProfileId() { + return profileId; + } + + @Persist + public void setProfileId(String fileName) { + this.profileId = fileName; + } + +}
--- a/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/ProfileRequest.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/ProfileRequest.java Tue Nov 18 14:07:31 2014 -0500 @@ -37,7 +37,6 @@ package com.redhat.thermostat.vm.profiler.common; import java.net.InetSocketAddress; -import java.util.Objects; import com.redhat.thermostat.common.command.Request; import com.redhat.thermostat.common.command.Request.RequestType;
--- a/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/Activator.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/Activator.java Tue Nov 18 14:07:31 2014 -0500 @@ -36,19 +36,48 @@ package com.redhat.thermostat.vm.profiler.common.internal; +import java.util.Map; + 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.common.MultipleServiceTracker; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; public class Activator implements BundleActivator { + private ServiceRegistration<ProfileDAO> daoRegistration; + private MultipleServiceTracker tracker; + @Override - public void start(BundleContext context) throws Exception { - // TODO implement me + public void start(final BundleContext context) throws Exception { + Class<?>[] deps = new Class<?>[] { + Storage.class, + }; + tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() { + @Override + public void dependenciesAvailable(Map<String, Object> services) { + Storage storage = (Storage) services.get(Storage.class.getName()); + ProfileDAOImpl impl = new ProfileDAOImpl(storage); + + daoRegistration = context.registerService(ProfileDAO.class, impl, null); + } + @Override + public void dependenciesUnavailable() { + daoRegistration.unregister(); + daoRegistration = null; + } + }); + tracker.open(); } @Override public void stop(BundleContext context) throws Exception { - // TODO implement me + tracker.close(); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImpl.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,133 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common.internal; + +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.DescriptorParsingException; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.StatementExecutionException; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileInfo; + +public class ProfileDAOImpl implements ProfileDAO { + + private static final Logger logger = LoggingUtils.getLogger(ProfileDAOImpl.class); + + private static final Key<String> KEY_PROFILE_ID = new Key<>("profileId"); + + static final Category<ProfileInfo> CATEGORY = new Category<>( + "profile-info", + ProfileInfo.class, + Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, KEY_PROFILE_ID); + + static final String DESC_ADD_PROFILE_INFO = "" + + "ADD " + CATEGORY.getName() + " SET " + + " '" + Key.AGENT_ID.getName() + "' = ?s ," + + " '" + Key.VM_ID.getName() + "' = ?s ," + + " '" + Key.TIMESTAMP.getName() + "' = ?l ," + + " '" + KEY_PROFILE_ID.getName() + "' = ?s"; + + static final String DESC_QUERY_LATEST = "QUERY " + + CATEGORY.getName() + " WHERE '" + + Key.AGENT_ID.getName() + "' = ?s AND '" + + Key.VM_ID.getName() + "' = ?s SORT '" + + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; + + private final Storage storage; + + public ProfileDAOImpl(Storage storage) { + this.storage = storage; + this.storage.registerCategory(CATEGORY); + } + + @Override + public void saveProfileData(ProfileInfo info, InputStream data) { + storage.saveFile(info.getProfileId(), data); + addProfileInfoToStorage(info); + } + + private void addProfileInfoToStorage(ProfileInfo info) { + StatementDescriptor<ProfileInfo> desc = new StatementDescriptor<>(CATEGORY, DESC_ADD_PROFILE_INFO); + PreparedStatement<ProfileInfo> prepared; + try { + prepared = storage.prepareStatement(desc); + prepared.setString(0, info.getAgentId()); + prepared.setString(1, info.getVmId()); + prepared.setLong(2, info.getTimeStamp()); + prepared.setString(3, info.getProfileId()); + prepared.execute(); + } catch (DescriptorParsingException e) { + logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); + } + } + + @Override + public InputStream loadLatestProfileData(VmRef vm) { + StatementDescriptor<ProfileInfo> desc = new StatementDescriptor<>(CATEGORY, DESC_QUERY_LATEST); + PreparedStatement<ProfileInfo> prepared; + try { + prepared = storage.prepareStatement(desc); + prepared.setString(0, vm.getHostRef().getAgentId()); + prepared.setString(1, vm.getVmId()); + Cursor<ProfileInfo> cursor = prepared.executeQuery(); + if (!cursor.hasNext()) { + return null; + } + ProfileInfo info = cursor.next(); + String profileId = info.getProfileId(); + return storage.loadFile(profileId); + } catch (DescriptorParsingException e) { + logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); + } + return null; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplCategoryRegistration.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.auth.CategoryRegistration; + +public class ProfileDAOImplCategoryRegistration implements CategoryRegistration { + + @Override + public Set<String> getCategoryNames() { + Set<String> names = new HashSet<>(); + names.add(ProfileDAOImpl.CATEGORY.getName()); + return names; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplStatementDescriptorRegistration.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; + +public class ProfileDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, PreparedParameter[] params) { + if (descriptor.equals(ProfileDAOImpl.DESC_ADD_PROFILE_INFO) + || descriptor.equals(ProfileDAOImpl.DESC_QUERY_LATEST)) { + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + descriptor + "<-"); + } + } + + @Override + public Set<String> getStatementDescriptors() { + Set<String> results = new HashSet<>(); + results.add(ProfileDAOImpl.DESC_ADD_PROFILE_INFO); + results.add(ProfileDAOImpl.DESC_QUERY_LATEST); + return results; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.CategoryRegistration Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,1 @@ +com.redhat.thermostat.vm.profiler.common.internal.ProfileDAOImplCategoryRegistration \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,1 @@ +com.redhat.thermostat.vm.profiler.common.internal.ProfileDAOImplStatementDescriptorRegistration \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/test/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplCategoryRegistrationTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common.internal; + +import static org.junit.Assert.assertTrue; + +import java.util.Set; + +import org.junit.Test; + +public class ProfileDAOImplCategoryRegistrationTest { + + @Test + public void includesProfileInfoCategory() { + ProfileDAOImplCategoryRegistration registration = new ProfileDAOImplCategoryRegistration(); + Set<String> names = registration.getCategoryNames(); + assertTrue(names.contains(ProfileDAOImpl.CATEGORY.getName())); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/test/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplStatementDescriptorRegistrationTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common.internal; + +import static org.junit.Assert.assertTrue; + +import java.util.Set; + +import org.junit.Test; + +public class ProfileDAOImplStatementDescriptorRegistrationTest { + + @Test + public void includesProfileInfoCategory() { + ProfileDAOImplStatementDescriptorRegistration registration = new ProfileDAOImplStatementDescriptorRegistration(); + Set<String> names = registration.getStatementDescriptors(); + assertTrue(names.contains(ProfileDAOImpl.DESC_ADD_PROFILE_INFO)); + assertTrue(names.contains(ProfileDAOImpl.DESC_QUERY_LATEST)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/common/src/test/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplTest.java Tue Nov 18 14:07:31 2014 -0500 @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2014 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 + * <http://www.gnu.org/licenses/>. + * + * 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.vm.profiler.common.internal; + +public class ProfileDAOImplTest { + +}
--- a/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/InstrumentationControl.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/InstrumentationControl.java Tue Nov 18 14:07:31 2014 -0500 @@ -36,11 +36,22 @@ package com.redhat.thermostat.vm.profiler.agent.jvm; +import java.io.BufferedWriter; +import java.io.IOException; import java.lang.instrument.Instrumentation; import java.lang.instrument.UnmodifiableClassException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; public class InstrumentationControl implements InstrumentationControlMXBean { @@ -50,6 +61,8 @@ private boolean profiling = false; + private String lastResults = null; + public InstrumentationControl(Instrumentation instrumentation) { this.instrumentation = instrumentation; this.classInstrumentor = new AsmBasedInstrumentor(); @@ -60,6 +73,7 @@ } private void addShutdownHookToPrintStatsOnEnd() { + System.out.println("AGENT: adding shutdown hooks"); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { @@ -89,7 +103,7 @@ @Override public void stopProfiling() { - System.out.println("AGENT: stopProfiling()"); + System.out.println("AGENT: stopProfiling() called"); if (!profiling) { throw new IllegalStateException("Not profiling"); } @@ -97,13 +111,9 @@ instrumentation.removeTransformer(classInstrumentor); retransformAlreadyLoadedClasses(instrumentation, classInstrumentor); + + lastResults = writeProfilingResultsToDisk(); } - - @Override - public boolean isProfiling() { - return profiling; - } - private void retransformAlreadyLoadedClasses(Instrumentation instrumentation, ProfilerInstrumentor profiler) { long start = System.nanoTime(); @@ -140,4 +150,42 @@ System.out.println("AGENT: Retansforming took: " + (end - start) + "ns"); } + private String writeProfilingResultsToDisk() { + System.out.println("AGENT: Writing results to disk"); + try { + Path output = createOutput(); + OpenOption[] options = + new OpenOption[] { StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING }; + + try (BufferedWriter out = Files.newBufferedWriter(output, StandardCharsets.UTF_8, options)) { + Map<String, AtomicLong> data = ProfileRecorder.getInstance().getData(); + for (Map.Entry<String, AtomicLong> entry : data.entrySet()) { + out.write(entry.getValue().get() + "\t" + entry.getKey()); + } + System.out.println("AGENT: profiling data written to " + output.toString()); + return output.toString(); + } + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + private Path createOutput() throws IOException { + Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rw-------"); + FileAttribute<Set<PosixFilePermission>> attributes = PosixFilePermissions.asFileAttribute(perm); + return Files.createTempFile("thermostat", ".perfdata", attributes); + } + + @Override + public boolean isProfiling() { + return profiling; + } + + @Override + public String getProfilingDataFile() { + System.out.println("getProfilingDataFile() called. Returning : " + lastResults); + return lastResults; + } + }
--- a/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/InstrumentationControlMXBean.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/InstrumentationControlMXBean.java Tue Nov 18 14:07:31 2014 -0500 @@ -45,7 +45,9 @@ /** Disable profiling */ void stopProfiling(); - /** @returns whether profiling is currently active or not */ + /** @return whether profiling is currently active or not */ boolean isProfiling(); + /** @return the path to the profiling data file */ + String getProfilingDataFile(); }
--- a/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/ProfilerAgent.java Tue Nov 18 14:06:45 2014 -0500 +++ b/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/ProfilerAgent.java Tue Nov 18 14:07:31 2014 -0500 @@ -57,6 +57,9 @@ } private static void initializeAgent(String args, Instrumentation instrumentation) { + + System.out.println("AGENT: loaded"); + // This is the saner approach, but for now we are brute-forcing a // hardcoded path using a manifest entry // String jars = args;
--- a/web/war/pom.xml Tue Nov 18 14:06:45 2014 -0500 +++ b/web/war/pom.xml Tue Nov 18 14:07:31 2014 -0500 @@ -171,6 +171,11 @@ <artifactId>thermostat-vm-memory-common</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-vm-profiler-common</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> <build>