@Override
  public Sequence<T> run(final Query<T> query, final Map<String, Object> responseContext) {
    final Sequence<T> baseSequence = delegate.run(query, responseContext);
    return Sequences.withEffect(
        new Sequence<T>() {
          @Override
          public <OutType> OutType accumulate(
              OutType initValue, Accumulator<OutType, T> accumulator) {
            final long start = VMUtils.getCurrentThreadCpuTime();
            try {
              return baseSequence.accumulate(initValue, accumulator);
            } finally {
              cpuTimeAccumulator.addAndGet(VMUtils.getCurrentThreadCpuTime() - start);
            }
          }

          @Override
          public <OutType> Yielder<OutType> toYielder(
              OutType initValue, YieldingAccumulator<OutType, T> accumulator) {
            final Yielder<OutType> delegateYielder = baseSequence.toYielder(initValue, accumulator);
            return new Yielder<OutType>() {
              @Override
              public OutType get() {
                final long start = VMUtils.getCurrentThreadCpuTime();
                try {
                  return delegateYielder.get();
                } finally {
                  cpuTimeAccumulator.addAndGet(VMUtils.getCurrentThreadCpuTime() - start);
                }
              }

              @Override
              public Yielder<OutType> next(OutType initValue) {
                final long start = VMUtils.getCurrentThreadCpuTime();
                try {
                  return delegateYielder.next(initValue);
                } finally {
                  cpuTimeAccumulator.addAndGet(VMUtils.getCurrentThreadCpuTime() - start);
                }
              }

              @Override
              public boolean isDone() {
                return delegateYielder.isDone();
              }

              @Override
              public void close() throws IOException {
                delegateYielder.close();
              }
            };
          }
        },
        new Runnable() {
          @Override
          public void run() {
            if (report) {
              final long cpuTime = cpuTimeAccumulator.get();
              if (cpuTime > 0) {
                final ServiceMetricEvent.Builder builder =
                    Preconditions.checkNotNull(builderFn.apply(query));
                builder.setDimension(DruidMetrics.ID, Strings.nullToEmpty(query.getId()));
                emitter.emit(builder.build("query/cpu/time", cpuTimeAccumulator.get() / 1000));
              }
            }
          }
        },
        MoreExecutors.sameThreadExecutor());
  }