我是AspectJ的新手,我想弄清楚,如何保持/跟踪多个异步方法调用的上下文。想象一下以下代码:
@TimerStart
public void doSomething() throws InterruptedException {
Thread.sleep(1000);
MyCallable callable = new MyCallable();
Future future = executorService.submit(callable );
}
private class MyCallable implements Callable {
@Override
public Object call() throws Exception {
someOtherMethod();
return null;
}
@TimerEnd
private void someOtherMethod() throws InterruptedException {
Thread.sleep(1000);
}
}
我想衡量@TimerStart和@TimerEnd之间的时间。我现在正在努力解决两个问题:
目前我有类似的内容:
public aspect TimerAspect {
pointcut timerStart(Object object, TimerStart timed):
execution(@TimerStart * *(..)) && this(object) && @annotation(timed);
pointcut timerStop(Object object, TimerEnd timed):
cflow(execution(@TimerEnd * *(..)) && this(object) && @annotation(timed) && !within(FlowTimerAspect));
before(Object object, TimerStart timed): timerStart(object, timed) {
System.out.println("##### Flow timer START");
}
after(Object object, TimerEnd timed): timerStop(object, timed) {
System.out.println("##### Flow timer STOP");
}
然而,我现在唯一得到的是StackOverflowException(是的,我知道 - 这就是我在这里问的原因)。
编辑:
我偶然发现了percflow
,这似乎只是当@TimerStart和@TimerEnd出现在同一个线程中时才会发挥作用。建议非常感谢!!
public aspect TimerAspect percflow(timerStart(Object, TimerStart)) {
private long context;
pointcut timerStart(Object object, TimerStart timed):
execution(@TimerStart * *(..)) && this(object) && @annotation(timed);
pointcut timerStop(Object object, TimerEnd timed):
execution(@TimerEnd * *(..)) && this(object) && @annotation(timed);
before(Object object, TimerStart timed): timerStart(object, timed) {
context = System.currentTimeMillis();
}
after(Object object, TimerEnd timed): timerStop(object, timed) {
long passed = System.currentTimeMillis() - context;
System.out.println("passed time: " + passed);
}
}
答案 0 :(得分:2)
由于您计划在测量时切换线程,$ frama-c -pp-annot -wp -wp-rte -wp-timeout 100 search.c
[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing)
[kernel] Parsing search.c (with preprocessing)
/tmp/ppannot97a491.c:1:0: warning: "__STDC_VERSION__" redefined
#define __STDC_VERSION__ 201112L
^
<built-in>: note: this is the location of the previous definition
/tmp/ppannot97a491.c:2:0: warning: "__STDC_UTF_16__" redefined
#define __STDC_UTF_16__ 1
^
<built-in>: note: this is the location of the previous definition
/tmp/ppannot97a491.c:3:0: warning: "__STDC_UTF_32__" redefined
#define __STDC_UTF_32__ 1
^
<built-in>: note: this is the location of the previous definition
[wp] Running WP plugin...
[wp] Collecting axiomatic usage
[rte] annotating function main
[rte] annotating function search
[wp] 20 goals scheduled
[wp] [Qed] Goal typed_main_call_search_pre : Valid
[wp] [Qed] Goal typed_main_call_search_pre_2 : Valid
[wp] [Alt-Ergo] Goal typed_search_complete_found_nfound : Valid (10ms) (19)
[wp] [Alt-Ergo] Goal typed_search_loop_inv_preserved : Valid (17ms) (21)
[wp] [Alt-Ergo] Goal typed_search_disjoint_found_nfound : Valid (13ms) (19)
[wp] [Qed] Goal typed_search_loop_inv_established : Valid
[wp] [Qed] Goal typed_search_loop_inv_2_established : Valid
[wp] [Alt-Ergo] Goal typed_main_call_search_pre_3 : Valid (383ms) (93)
[wp] [Alt-Ergo] Goal typed_search_loop_inv_2_preserved : Valid (17ms) (33)
[wp] [Qed] Goal typed_search_loop_assign : Valid
[wp] [Alt-Ergo] Goal typed_search_assert_rte_mem_access : Valid (50ms) (89)
[wp] [Alt-Ergo] Goal typed_search_assert_rte_unsigned_overflow : Valid (13ms) (30)
[wp] [Qed] Goal typed_search_assign_part1 : Valid
[wp] [Qed] Goal typed_search_assign_part2 : Valid
[wp] [Qed] Goal typed_search_assign_part3 : Valid
[wp] [Qed] Goal typed_search_assign_part4 : Valid
[wp] [Qed] Goal typed_search_loop_term_decrease : Valid (3ms)
[wp] [Qed] Goal typed_search_loop_term_positive : Valid
[wp] [Alt-Ergo] Goal typed_search_nfound_post : Valid (17ms) (33)
[wp] [Alt-Ergo] Goal typed_search_found_post : Unknown (54.3s)
[wp] Proved goals: 19 / 20
Qed: 11 (3ms-3ms)
Alt-Ergo: 8 (10ms-383ms) (93) (unknown: 1)
实例化方法不会对您有所帮助。您必须坚持使用默认的单例方面,并将感兴趣对象的计时值保存在percflow
中。这样,只要与时间相关联的对象/线程处于活动状态,就可以保持时间。
我们需要另一个注释来标记将新对象(在此示例中为WeakHashMap
)与您的时间相关联的事件。我们称之为Callable
。 @TimerJoin
注释类似于您现有的@TimerJoin
和@TimerStart
注释。您的测量方面将如下所示。
@TimerEnd
简单的import java.util.Map;
import java.util.WeakHashMap;
public aspect TimerAspect {
private final Map<Object, Timer> objectTiming = new WeakHashMap<>();
private final ThreadLocal<Timer> currentThreadTimer = new ThreadLocal<>();
pointcut timerStart(Object object):
execution(@TimerStart * *(..)) && this(object);
pointcut timerStop(Object object):
execution(@TimerEnd * *(..)) && this(object);
pointcut timerJoin(Object object):
(execution(@TimerJoin * *(..)) || execution(@TimerJoin *.new(..)) )
&& this(object);
before(Object object): timerStart(object) {
Timer timer = new Timer();
timer.start();
objectTiming.put(object, timer);
currentThreadTimer.set(timer);
System.out.println("##### Flow timer START");
}
before(Object object): timerJoin(object) {
Timer timing = currentThreadTimer.get();
objectTiming.put(object, timing);
System.out.println("##### Flow timer JOIN");
}
after(Object object): timerStop(object) {
Timer timing = objectTiming.get(object);
timing.stop();
System.out.println("##### Flow timer STOP");
System.out.println("Elapsed: " + timing.getElapsed());
}
}
类:
Timer.java
修改你的callable以将其标记为加入当前线程上的计时器:
public class Timer {
private long start;
private long stop;
public long getStart() {
return start;
}
public long getStop() {
return stop;
}
public void start() {
start = System.currentTimeMillis();
}
public void stop() {
stop = System.currentTimeMillis();
}
public long getElapsed() {
return stop-start;
}
}
其余代码将是相同的。
您可能会注意到方面正在使用private class MyCallable implements Callable {
@TimerJoin
public MyCallable() {
}
@Override
public Object call() throws Exception {
someOtherMethod();
return null;
}
@TimerEnd
private void someOtherMethod() throws InterruptedException {
Thread.sleep(1000);
}
}
作为存储方式,以便当前计时器能够将其与新对象相关联。您可以为此选择另一种存储,但为了示例,我试图保持简单。此外,为了简单起见,我省略了对方面的空值的任何安全检查。你需要自己处理角落案件。