/** * Copyright (c) 2014, the Railo Company Ltd. * Copyright (c) 2015, Lucee Assosication Switzerland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.runtime.engine; import java.util.Collections; import java.util.HashMap; import java.util.Map; import lucee.commons.io.SystemUtil; import lucee.commons.lang.StringUtil; import lucee.runtime.PageContext; import lucee.runtime.op.Caster; public abstract class ExecutionLogSupport implements ExecutionLog { protected static final short UNIT_NANO=1; protected static final short UNIT_MICRO=2; protected static final short UNIT_MILLI=4; protected static final short UNIT_UNDEFINED=0; private Map<String,Pair> map=Collections.synchronizedMap(new HashMap<String,Pair>()); protected long min=Long.MIN_VALUE; protected short unit=UNIT_UNDEFINED; @Override public void init(PageContext pc,Map<String,String> arguments) { // min if(min==Long.MIN_VALUE) { min=toNanos(arguments.get("min-time"),0); } // unit if(UNIT_UNDEFINED==unit){ unit=UNIT_NANO; // unit String _unit=arguments.get("unit"); if(_unit!=null) { _unit=_unit.trim(); if(_unit.equalsIgnoreCase("micro")) unit=UNIT_MICRO; else if(_unit.equalsIgnoreCase(SystemUtil.SYMBOL_MICRO+"s")) unit=UNIT_MICRO; else if(_unit.equalsIgnoreCase("milli"))unit=UNIT_MILLI; else if(_unit.equalsIgnoreCase("ms")) unit=UNIT_MILLI; } } _init(pc,arguments); } private static long toNanos(String str, int defaultValue) { if(StringUtil.isEmpty(str)) return defaultValue; str=str.trim().toLowerCase(); long l = Caster.toLongValue(str,Long.MIN_VALUE); if(l!=Long.MIN_VALUE) return l; if(str.endsWith("ns")) { String sub=str.substring(0,str.length()-2); l = Caster.toLongValue(sub.trim(),Long.MIN_VALUE); if(l!=Long.MIN_VALUE) return l; } else if(str.endsWith(SystemUtil.SYMBOL_MICRO+"s")) { String sub=str.substring(0,str.length()-2); double d = Caster.toDoubleValue(sub.trim(),Double.NaN); if(!Double.isNaN(d)) return (long)(d*1000); } else if(str.endsWith("ms")) { String sub=str.substring(0,str.length()-2); double d = Caster.toDoubleValue(sub.trim(),Double.NaN); if(!Double.isNaN(d)) return (long)(d*1000*1000); } else if(str.endsWith("s")) { String sub=str.substring(0,str.length()-1); double d = Caster.toDoubleValue(sub.trim(),Double.NaN); if(!Double.isNaN(d)) return (long)(d*1000*1000); } return defaultValue; } @Override public final void release() { map.clear(); _release(); } @Override public final void start(int pos,String id) { long current = System.nanoTime(); map.put(id,new Pair(current,pos)); } @Override public final void end(int pos,String id) { long current = System.nanoTime(); Pair pair=map.remove(id); if(pair!=null) { if((current-pair.time)>=min) _log(pair.pos,pos,pair.time,current); } } protected abstract void _init(PageContext pc, Map<String, String> arguments); protected abstract void _log(int startPos, int endPos, long startTime, long endTime); protected abstract void _release(); protected String timeLongToString(long current) { if(unit==UNIT_MICRO) return (current/1000L)+" "+SystemUtil.SYMBOL_MICRO+"s"; if(unit==UNIT_MILLI) return (current/1000000L)+" ms"; return current+" ns"; } protected static String unitShortToString(short unit) { if(unit==UNIT_MICRO) return SystemUtil.SYMBOL_MICRO+"s"; if(unit==UNIT_MILLI) return "ms"; return "ns"; } private final static class Pair { private final long time; private final int pos; public Pair(long time, int pos) { this.time=time; this.pos=pos; } } }