public Object invokeAdvice(Method method, Object invoker) throws Throwable
    {
        Object result;

        final long tid = Thread.currentThread().getId();
        final ThreadMXBean bean = ManagementFactory.getThreadMXBean();

        MethodInfo caller = null;
        
        if (Cpu.getInstance().getThreadProfiler(tid) != null)
        {
            caller = Cpu.getInstance().getThreadProfiler(tid).peekMethodInfo();
        } 
        
        final MethodInfo called = Cpu.getInstance().monitor(method, caller);
        
        called.setTimes(new Times(tid));

        try
        {
            if (bean != null)
            {
                called.getTimes().setCpuTime(new Period(bean.getCurrentThreadCpuTime()));
                called.getTimes().setUserTime(new Period(bean.getCurrentThreadUserTime()));
            }

            if (caller != null)
            {
                caller.getTimer().suspend();
            }
            
            called.getTimer().restart();
            result = proceed(invoker);
        }
        finally
        {
            called.getTimer().stop();
            Cpu.getInstance().getThreadProfiler(tid).popStack();
            
            if (bean != null)
            {
                long cpuTime = bean.getCurrentThreadCpuTime();
                long userTime = bean.getCurrentThreadUserTime();

                called.getTimes().getCpuTime().setEndTime(cpuTime);
                called.getTimes().getUserTime().setEndTime(userTime);
            }

            if ("main".equalsIgnoreCase(method.getName()))
            {
                Cpu.getInstance().getThreadProfiler(tid).stop(called.getTimes().getUserTime().time());
                Cpu.getInstance().getThread(tid).getTimer().stop();
            }
            
            if (caller != null)
            {
                caller.getTimer().resume();
            }
        }
        return result;
    }