com.caucho.admin.action.ProfileAction Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source 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 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
*/
package com.caucho.admin.action;
import java.io.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.caucho.config.ConfigException;
import com.caucho.profile.*;
import com.caucho.util.*;
public class ProfileAction implements AdminAction
{
private static final Logger log
= Logger.getLogger(ProfileAction.class.getName());
private static final L10N L = new L10N(ProfileAction.class);
private AtomicLong _cancelledTime = new AtomicLong(-1);
private boolean _isProfileDisabled;
public void cancel()
{
_cancelledTime.compareAndSet(-1, CurrentTime.getCurrentTime());
synchronized(this) {
this.notify();
}
Profile profile = Profile.createProfile();
if (profile != null)
profile.stop();
}
public void start(long samplingRate, int depth)
{
Profile profile = Profile.createProfile();
profile.stop();
profile.setPeriod(samplingRate);
profile.setDepth(depth);
profile.start();
}
public String execute(long activeTime, long samplingRate, int depth)
throws ConfigException
{
if (activeTime <= 0) {
throw new IllegalArgumentException(L.l("Profile activeTime '{0}': must be > 0.",
activeTime));
}
Profile profile = null;
try {
if (! _isProfileDisabled) {
profile = Profile.createProfile();
}
} catch (Throwable e) {
_isProfileDisabled = true;
log.warning(e.toString());
log.log(Level.FINER, e.toString(), e);
}
if (profile == null) {
return null;
}
if (profile.isActive()) {
throw new ConfigException(L.l("Profile is still active"));
}
long startedAt = CurrentTime.getCurrentTime();
start(samplingRate, depth);
try {
synchronized (this) {
this.wait(activeTime);
}
} catch (InterruptedException e) {
_cancelledTime.compareAndSet(-1, CurrentTime.getCurrentTime());
}
profile.stop();
StringWriter buffer = new StringWriter();
PrintWriter out = new PrintWriter(buffer);
ProfileEntry []entries = profile.getResults();
if (entries == null || entries.length == 0) {
out.println("Profile returned no entries.");
}
else {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
long cancelledTime = _cancelledTime.get();
if (cancelledTime < 0) {
out.print(L.l("Profile started at {0}. Active for a total of {1}ms.",
dateFormat.format(new Date(startedAt)),
activeTime));
}
else {
long et = cancelledTime - startedAt;
out.print(L.l("Profile started at {0}, cancelled at {1}. Active for a total of {2}ms.",
dateFormat.format(new Date(startedAt)),
dateFormat.format(new Date(cancelledTime)),
et));
}
out.println(L.l(" Sampling rate {0}ms. Depth {1}.",
samplingRate,
String.valueOf(depth)));
double totalTicks = 0;
for (ProfileEntry entry : entries) {
totalTicks += entry.getCount();
}
final double sampleTicks = profile.getTicks();
double totalPercent = 0d;
out.println(" ref# | % time |time self(s)| % sum | Method Call");
for (int i = 0; i < entries.length; i++) {
ProfileEntry entry = entries[i];
double timePercent = (double) 100 * (double) entry.getCount()
/ sampleTicks;
double selfPercent = (double) 100 * (double) entry.getCount()
/ totalTicks;
totalPercent += selfPercent;
out.println(String.format(" %4d | %10.3f | %10.3f | %10.3f | %s",
i,
timePercent,
(float) entry.getCount() * samplingRate * 0.001,
totalPercent,
entry.getDescription()));
}
for (int i = 0; i < entries.length; i++) {
ProfileEntry entry = entries[i];
out.print(String.format(" %4d ", i));
out.println(" " + entry.getDescription());
ArrayList extends StackEntry> stackEntries = entry.getStackTrace();
for (StackEntry stackEntry : stackEntries) {
out.println(" " + stackEntry.getDescription());
}
}
}
out.flush();
return buffer.toString();
}
/**
* @return
*/
public String jsonProfile()
{
Profile profile = Profile.createProfile();
if (profile == null)
return null;
ProfileEntry []entries = profile.getResults();
if (entries == null || entries.length == 0) {
return null;
}
StringBuilder sb = new StringBuilder();
long timestamp = CurrentTime.getCurrentTime();
sb.append("{\n");
sb.append(" \"create_time\": \"" + new Date(timestamp) + "\"");
sb.append(",\n \"timestamp\": " + timestamp);
sb.append(",\n \"ticks\" : " + profile.getTicks());
sb.append(",\n \"depth\" : " + profile.getDepth());
sb.append(",\n \"period\" : " + profile.getPeriod());
sb.append(",\n \"end_time\" : " + profile.getEndTime());
sb.append(",\n \"gc_time\" : " + profile.getGcTime());
sb.append(",\n \"profile\" : [\n");
for (int i = 0; i < entries.length; i++) {
if (i != 0)
sb.append(",\n");
jsonEntry(sb, entries[i]);
}
/*
long gcTicks = (profile.getGcTime() + profile.getPeriod() - 1)
/ profile.getPeriod();
if (entries.length > 0)
sb.append(",\n");
jsonGc(sb, gcTicks);
*/
sb.append("\n ]");
sb.append("\n}");
return sb.toString();
}
private void jsonEntry(StringBuilder sb, ProfileEntry entry)
{
sb.append("{");
sb.append("\n \"name\" : \"");
escapeString(sb, entry.getDescription());
sb.append("\"");
sb.append(",\n \"ticks\" : " + entry.getCount());
sb.append(",\n \"state\" : \"" + entry.getState() + "\"");
if (entry.getStackTrace() != null && entry.getStackTrace().size() > 0) {
jsonStackTrace(sb, entry.getStackTrace());
}
sb.append("\n}");
}
private void jsonGc(StringBuilder sb, long ticks)
{
sb.append("{");
sb.append("\n \"name\" : \"HeapMemory.gc\"");
sb.append(",\n \"ticks\" : " + ticks);
sb.append(",\n \"state\" : \"RUNNABLE\"");
sb.append("\n}");
}
private void jsonStackTrace(StringBuilder sb,
ArrayList extends StackEntry> stack)
{
sb.append(",\n \"stack\" : ");
sb.append("[\n");
int size = stack.size();
for (int i = 0; i < size; i++) {
StackEntry entry = stack.get(i);
if (i != 0)
sb.append(",\n");
sb.append(" {");
sb.append("\n \"class\" : \"" + entry.getClassName() + "\"");
sb.append(",\n \"method\" : \"" + entry.getMethodName() + "\"");
if (entry.getArg() != null && ! "".equals(entry.getArg())) {
sb.append(",\n \"arg\" : \"");
escapeString(sb, entry.getArg());
sb.append("\"");
}
sb.append("\n }");
}
sb.append("\n ]");
}
private void escapeString(StringBuilder sb, String value)
{
if (value == null)
return;
int len = value.length();
for (int i = 0; i < len; i++) {
char ch = value.charAt(i);
switch (ch) {
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
default:
sb.append(ch);
break;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy