You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by su...@apache.org on 2019/06/06 08:18:47 UTC

[incubator-iotdb] branch time_statstic updated: jmx dynamic control parameter and function

This is an automated email from the ASF dual-hosted git repository.

suyue pushed a commit to branch time_statstic
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git


The following commit(s) were added to refs/heads/time_statstic by this push:
     new 1fe9860  jmx dynamic control parameter and function
1fe9860 is described below

commit 1fe986058f6d710995aa55c2594d49e0c331ee8f
Author: suyue <23...@qq.com>
AuthorDate: Thu Jun 6 16:17:52 2019 +0800

    jmx dynamic control parameter and function
---
 iotdb/iotdb/conf/iotdb-engine.properties           |   4 +-
 iotdb/iotdb/conf/logback.xml                       |   2 +-
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java |  27 +-
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |   9 +-
 .../apache/iotdb/db/cost/stastic/Measurement.java  | 144 --------
 .../iotdb/db/cost/statistic/Measurement.java       | 387 +++++++++++++++++++++
 .../iotdb/db/cost/statistic/MeasurementMBean.java  |  46 +++
 .../db/cost/{stastic => statistic}/Operation.java  |   2 +-
 .../org/apache/iotdb/db/cost/statistic/Test.java   |  35 ++
 .../iotdb/db/engine/filenode/FileNodeManager.java  |   4 +-
 .../org/apache/iotdb/db/qp/QueryProcessor.java     |   4 +-
 .../iotdb/db/qp/executor/OverflowQPExecutor.java   |   4 +-
 .../java/org/apache/iotdb/db/service/IoTDB.java    |   2 +
 .../org/apache/iotdb/db/service/ServiceType.java   |   3 +-
 .../org/apache/iotdb/db/service/TSServiceImpl.java |   4 +-
 15 files changed, 511 insertions(+), 166 deletions(-)

diff --git a/iotdb/iotdb/conf/iotdb-engine.properties b/iotdb/iotdb/conf/iotdb-engine.properties
index f97b542..f8bca91 100644
--- a/iotdb/iotdb/conf/iotdb-engine.properties
+++ b/iotdb/iotdb/conf/iotdb-engine.properties
@@ -222,6 +222,8 @@ update_historical_data_possibility=false
 
 # performance statistic configuration
 # Is stat time cost of sub-module in write process enable
-enable_write_performance_stat=true
+enable_performance_stat=false
 # The interval of small flush in ms.
 performance_stat_display_interval=60000
+# The memory used for performance_stat.
+performance_stat_memory_in_kb=20
diff --git a/iotdb/iotdb/conf/logback.xml b/iotdb/iotdb/conf/logback.xml
index 7e04838..ff7c459 100644
--- a/iotdb/iotdb/conf/logback.xml
+++ b/iotdb/iotdb/conf/logback.xml
@@ -153,7 +153,7 @@
         <appender-ref ref="FILEALL"/>
         <appender-ref ref="stdout"/>
     </root>
-    <logger level="info" name="org.apache.iotdb.db.cost.stastic">
+    <logger level="info" name="org.apache.iotdb.db.cost.statistic">
         <appender-ref ref="FILE_COST_MEASURE"/>
     </logger>
 </configuration>
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 178d517..22b0bab 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -283,15 +283,20 @@ public class IoTDBConfig {
   private String rpcImplClassName = TSServiceImpl.class.getName();
 
   /**
-   * Is stat time cost of sub-module in write process enable.
+   * Is stat performance of sub-module enable.
    */
-  private boolean enableWritePerformanceStat = false;
+  private boolean enablePerformanceStat = false;
 
   /**
-   * The display of stat time cost interval in ms.
+   * The display of stat performance interval in ms.
    */
   private long performanceStatDisplayInterval = 60000;
 
+  /**
+   * The memory used for stat performance.
+   */
+  private int performance_stat_memory_in_kb = 20;
+
   public IoTDBConfig() {
     // empty constructor
   }
@@ -840,12 +845,12 @@ public class IoTDBConfig {
     this.rpcImplClassName = rpcImplClassName;
   }
 
-  public boolean isEnableWritePerformanceStat() {
-    return enableWritePerformanceStat;
+  public boolean isEnablePerformanceStat() {
+    return enablePerformanceStat;
   }
 
-  public void setEnableWritePerformanceStat(boolean enableWritePerformanceStat) {
-    this.enableWritePerformanceStat = enableWritePerformanceStat;
+  public void setEnablePerformanceStat(boolean enablePerformanceStat) {
+    this.enablePerformanceStat = enablePerformanceStat;
   }
 
   public long getPerformanceStatDisplayInterval() {
@@ -855,4 +860,12 @@ public class IoTDBConfig {
   public void setPerformanceStatDisplayInterval(long performanceStatDisplayInterval) {
     this.performanceStatDisplayInterval = performanceStatDisplayInterval;
   }
+
+  public int getPerformance_stat_memory_in_kb() {
+    return performance_stat_memory_in_kb;
+  }
+
+  public void setPerformance_stat_memory_in_kb(int performance_stat_memory_in_kb) {
+    this.performance_stat_memory_in_kb = performance_stat_memory_in_kb;
+  }
 }
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index 571012c..0f1d752 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -251,13 +251,16 @@ public class IoTDBDescriptor {
             conf.getZoneID(), e);
       }
 
-      conf.setEnableWritePerformanceStat(Boolean
-          .parseBoolean(properties.getProperty("enable_write_performance_stat",
-              Boolean.toString(conf.isEnableWritePerformanceStat())).trim()));
+      conf.setEnablePerformanceStat(Boolean
+          .parseBoolean(properties.getProperty("enable_performance_stat",
+              Boolean.toString(conf.isEnablePerformanceStat())).trim()));
 
       conf.setPerformanceStatDisplayInterval(Long
           .parseLong(properties.getProperty("performance_stat_display_interval",
               Long.toString(conf.getPerformanceStatDisplayInterval())).trim()));
+      conf.setPerformance_stat_memory_in_kb(Integer
+          .parseInt(properties.getProperty("performance_stat_memory_in_kb",
+              Integer.toString(conf.getPerformance_stat_memory_in_kb())).trim()));
     } catch (IOException e) {
       LOGGER.warn("Cannot load config file because, use default configuration", e);
     } catch (Exception e) {
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/cost/stastic/Measurement.java b/iotdb/src/main/java/org/apache/iotdb/db/cost/stastic/Measurement.java
deleted file mode 100644
index fba0493..0000000
--- a/iotdb/src/main/java/org/apache/iotdb/db/cost/stastic/Measurement.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.cost.stastic;
-
-import java.util.Date;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import org.apache.iotdb.db.concurrent.IoTDBThreadPoolFactory;
-import org.apache.iotdb.db.concurrent.ThreadName;
-import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Measurement {
-
-  /**
-   * queue for store time latrncies async.
-   */
-  private Queue<Long>[] operationLatenciesQueue;
-
-  /**
-   * latencies sum of each operation.
-   */
-  private long[] operationLatencies;
-
-  /**
-   * count of each operation.
-   */
-  private long[] operationCnt;
-
-  /**
-   * display thread.
-   */
-  private ScheduledExecutorService service;
-
-  public static final Measurement INSTANCE = AsyncMeasurementHolder.MEASUREMENT;
-
-  private boolean isEnableStat;
-  private long displayIntervalInMs;
-  private static final Logger LOGGER = LoggerFactory.getLogger(Measurement.class);
-
-
-
-  private Measurement(){
-    isEnableStat = IoTDBDescriptor.getInstance().getConfig().isEnableWritePerformanceStat();
-    if (isEnableStat) {
-      displayIntervalInMs = IoTDBDescriptor.getInstance().getConfig().getPerformanceStatDisplayInterval();
-      operationLatenciesQueue = new ConcurrentLinkedQueue[Operation.values().length];
-      operationLatencies = new long[Operation.values().length];
-      operationCnt = new long[Operation.values().length];
-      for (Operation op : Operation.values()){
-        operationLatenciesQueue[op.ordinal()] = new ConcurrentLinkedQueue<>();
-        operationCnt[op.ordinal()] = 0;
-        operationLatencies[op.ordinal()] = 0;
-      }
-
-      for (int i =0; i <operationLatenciesQueue.length; i++) {
-        new Thread(new NumThread(i)).start();
-      }
-
-      service = IoTDBThreadPoolFactory.newScheduledThreadPool(1,
-          ThreadName.TIME_COST_STATSTIC.getName());
-      service.scheduleWithFixedDelay(
-          new Measurement.DisplayRunnable(), 10, displayIntervalInMs, TimeUnit.MILLISECONDS);
-      System.out.println("init finish!");
-    }
-  }
-  class NumThread implements  Runnable{
-    int i;
-    public NumThread(int i) {
-      this.i = i;
-    }
-
-    @Override
-    public void run() {
-      Queue<Long> queue = operationLatenciesQueue[i];
-      while (true) {
-        Long time = queue.poll();
-        if (time != null) {
-          operationLatencies[i] += time;
-          operationCnt[i]++;
-        }else {
-          try {
-            Thread.sleep(10);
-          } catch (InterruptedException e) {
-          }
-        }
-      }
-    }
-  }
-
-  public void addOperationLatency(Operation op, long startTime) {
-    if (isEnableStat) {
-      operationLatenciesQueue[op.ordinal()].add((System.nanoTime() - startTime));
-    }
-  }
-
-  private static class  AsyncMeasurementHolder{
-    private static final Measurement MEASUREMENT = new Measurement();
-    private AsyncMeasurementHolder(){}
-  }
-
-  public void showMeasurements() {
-    Date date = new Date();
-    LOGGER.info("====================================={} Measurement (ms)======================================", date.toString());
-    String head = String.format("%-45s%-30s%-30s%-30s","OPERATION", "COUNT", "TOTAL_TIME", "AVG_TIME");
-    LOGGER.info(head);
-    for(Operation operation : Operation.values()){
-      long cnt = operationCnt[operation.ordinal()];
-      long totalInMs = 0;
-      totalInMs = operationLatencies[operation.ordinal()] / 1000000;
-      String avg = String.format("%.4f", (totalInMs/(cnt+1e-9)));
-      String item = String.format("%-45s%-30s%-30s%-30s", operation.name, cnt+"", totalInMs+"", avg);
-      LOGGER.info(item);
-    }
-    LOGGER.info(
-        "=================================================================================================================");
-  }
-
-  class DisplayRunnable implements Runnable{
-    @Override
-    public void run() {
-      showMeasurements();
-    }
-  }
-}
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Measurement.java b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Measurement.java
new file mode 100644
index 0000000..650bb3e
--- /dev/null
+++ b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Measurement.java
@@ -0,0 +1,387 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.cost.statistic;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.iotdb.db.concurrent.IoTDBThreadPoolFactory;
+import org.apache.iotdb.db.concurrent.ThreadName;
+import org.apache.iotdb.db.conf.IoTDBConfig;
+import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.exception.StartupException;
+import org.apache.iotdb.db.service.IService;
+import org.apache.iotdb.db.service.JMXService;
+import org.apache.iotdb.db.service.ServiceType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <p>
+ * Measurement is used to record execution time of operations defined in enum class Operation.
+ * It can display average time of each operation, and proportion of operation whose execution time
+ * fall into time range defined in BUCKET_IN_MS. If you want to change abscissa of histogram, just
+ * change the BUCKET_IN_MS array.
+ * For recording a operation, you should:
+ * 1) add a item in enum class Operation.
+ * 2) call <code>startTimeInNano = System.nanoTime()</code> to recode startTime of that operation.
+ * 3) call <code>Measurement.INSTANCE.addOperationLatency(operation, startTimeInNano)</code> at the
+ * end of that operation;
+ * @see Operation
+ */
+public class Measurement implements MeasurementMBean, IService {
+
+  /**
+   * queue for async store time latencies.
+   */
+  private Queue<Long>[] operationLatenciesQueue;
+
+  /**
+   * size of each queue, this is calculated by memory.
+   */
+  private final long QUEUE_SIZE;
+
+  /**
+   * latencies sum of each operation.
+   */
+  private long[] operationLatencies;
+
+  /**
+   * the num of each operation.
+   */
+  private long[] operationCnt;
+
+  /**
+   * abscissa of histogram.
+   */
+  private final int BUCKET_IN_MS[] = {1, 4, 16, 64, 256, 1024, Integer.MAX_VALUE};
+
+  /**
+   * length of BUCKET_IN_MS.
+   */
+  private final int BUCKET_SIZE = BUCKET_IN_MS.length;
+
+  /**
+   * the num of operation that execution time falls into time range of BUCKET_IN_MS. The outer array
+   * is each operation, the inner array is each time range in BUCKET_IN_MS.
+   */
+  private long[][] operationHistogram;
+
+  /**
+   * display thread and queue consumer thread.
+   */
+  private ScheduledExecutorService service;
+
+  /**
+   * future task of display thread and queue consumer thread.
+   */
+  private List<Future<?>> futureList;
+
+  /**
+   * lock for change state: start() and stopStatistic().
+   */
+  private ReentrantLock stateChangeLock = new ReentrantLock();
+
+  public static final Measurement INSTANCE = AsyncMeasurementHolder.MEASUREMENT;
+
+  private boolean isEnableStat;
+  private long displayIntervalInMs;
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(Measurement.class);
+  private final int MS_TO_NANO = 1000_000;
+  private final String mbeanName = String
+      .format("%s:%s=%s", "org.apache.iotdb.db.cost.statistic", IoTDBConstant.JMX_TYPE,
+          getID().getJmxName());
+
+  private Measurement() {
+    IoTDBConfig tdbConfig = IoTDBDescriptor.getInstance().getConfig();
+    isEnableStat = tdbConfig.isEnablePerformanceStat();
+    displayIntervalInMs = tdbConfig.getPerformanceStatDisplayInterval();
+    int memory_in_kb = tdbConfig.getPerformance_stat_memory_in_kb();
+
+    QUEUE_SIZE = memory_in_kb * 1000 / Operation.values().length / 8;
+    operationLatenciesQueue = new ConcurrentLinkedQueue[Operation.values().length];
+    operationLatencies = new long[Operation.values().length];
+    operationCnt = new long[Operation.values().length];
+    for (Operation op : Operation.values()) {
+      operationLatenciesQueue[op.ordinal()] = new ConcurrentLinkedQueue<>();
+      operationCnt[op.ordinal()] = 0;
+      operationLatencies[op.ordinal()] = 0;
+    }
+    operationHistogram = new long[Operation.values().length][BUCKET_SIZE];
+    for (Operation operation : Operation.values()) {
+      for (int i = 0; i < BUCKET_SIZE; i++) {
+        operationHistogram[operation.ordinal()][i] = 0;
+      }
+    }
+
+    service = IoTDBThreadPoolFactory.newScheduledThreadPool(
+        2, ThreadName.TIME_COST_STATSTIC.getName());
+    futureList = new ArrayList<>();
+  }
+
+  public void addOperationLatency(Operation op, long startTime) {
+    if (isEnableStat && operationLatenciesQueue[op.ordinal()].size() < QUEUE_SIZE) {
+      operationLatenciesQueue[op.ordinal()].add((System.nanoTime() - startTime));
+    }
+  }
+
+  @Override
+  public void startContinuousStatistics() {
+    stateChangeLock.lock();
+    try {
+      if (isEnableStat) {
+        return;
+      }
+      isEnableStat = true;
+      futureList.clear();
+      Future future = service.scheduleWithFixedDelay(
+          new Measurement.DisplayRunnable(), 20, displayIntervalInMs, TimeUnit.MILLISECONDS);
+      futureList.add(future);
+      futureList.add(service.schedule(new QueueConsumerThread(), 10, TimeUnit.MILLISECONDS));
+
+
+    } catch (Exception e) {
+      LOGGER.error("Find error when start performance statistic thread, because {}", e);
+    } finally {
+      stateChangeLock.unlock();
+    }
+  }
+
+  @Override
+  public void startOneTimeStatistics(){
+    stateChangeLock.lock();
+    try {
+      if (isEnableStat) {
+        return;
+      }
+      isEnableStat = true;
+      futureList.clear();
+      futureList.add(service.schedule(new QueueConsumerThread(), 10, TimeUnit.MILLISECONDS));
+      Future future = service.schedule(()->{
+        showMeasurements();
+          stopStatistic();
+          }, displayIntervalInMs, TimeUnit.MILLISECONDS);
+      futureList.add(future);
+    } catch (Exception e) {
+      LOGGER.error("Find error when start performance statistic thread, because {}", e);
+    } finally {
+      stateChangeLock.unlock();
+    }
+  }
+
+  @Override
+  public void stopStatistic() {
+    stateChangeLock.lock();
+    try {
+      if(isEnableStat == false){
+        return;
+      }
+      isEnableStat = false;
+      for (Future future : futureList) {
+        if (future != null) {
+          future.cancel(true);
+
+        }
+      }
+    } catch (Exception e) {
+      LOGGER.error("Find error when stopStatistic time cost statstic thread, because {}", e);
+    } finally {
+      stateChangeLock.unlock();
+    }
+
+  }
+
+  /**
+   * start service.
+   */
+  @Override
+  public void start() throws StartupException {
+    // start display thread and consumer threads.
+    if (isEnableStat) {
+      Future future = service.scheduleWithFixedDelay(
+          new Measurement.DisplayRunnable(), 20, displayIntervalInMs, TimeUnit.MILLISECONDS);
+      futureList.add(future);
+      futureList.add(service.schedule(new QueueConsumerThread(), 10, TimeUnit.MILLISECONDS));
+
+    }
+    try {
+      JMXService.registerMBean(INSTANCE, mbeanName);
+    } catch (Exception e) {
+      String errorMessage = String
+          .format("Failed to start %s because of %s", this.getID().getName(),
+              e.getMessage());
+      throw new StartupException(errorMessage, e);
+    }
+  }
+
+  /**
+   * stop service.
+   */
+  @Override
+  public void stop() {
+    JMXService.deregisterMBean(mbeanName);
+    if (service == null || service.isShutdown()) {
+      return;
+    }
+    stopStatistic();
+    futureList.clear();
+    service.shutdownNow();
+    try {
+      service.awaitTermination(5, TimeUnit.SECONDS);
+    } catch (InterruptedException e) {
+      LOGGER.error("Performance statistic service could not be shutdown, {}", e.getMessage());
+      // Restore interrupted state...
+      Thread.currentThread().interrupt();
+    }
+  }
+
+  @Override
+  public ServiceType getID() {
+    return ServiceType.PERFORMANCE_STATISTIC_SERVICE;
+  }
+
+  @Override
+  public boolean isEnableStat() {
+    return isEnableStat;
+  }
+
+  @Override
+  public void setEnableStat(boolean enableStat) {
+    isEnableStat = enableStat;
+  }
+
+  public long getDisplayIntervalInMs() {
+    return displayIntervalInMs;
+  }
+
+  public void setDisplayIntervalInMs(long displayIntervalInMs) {
+    this.displayIntervalInMs = displayIntervalInMs;
+  }
+
+  private static class AsyncMeasurementHolder {
+
+    private static final Measurement MEASUREMENT = new Measurement();
+
+    private AsyncMeasurementHolder() {
+    }
+  }
+
+  private void showMeasurements() {
+    Date date = new Date();
+    LOGGER.info(
+        "====================================={} Measurement (ms)======================================",
+        date.toString());
+    String head = String
+        .format("%-45s%-25s%-25s%-25s", "OPERATION", "COUNT", "TOTAL_TIME", "AVG_TIME");
+    LOGGER.info(head);
+    for (Operation operation : Operation.values()) {
+      long cnt = operationCnt[operation.ordinal()];
+      long totalInMs = 0;
+      totalInMs = operationLatencies[operation.ordinal()] / 1000000;
+      String avg = String.format("%.4f", (totalInMs / (cnt + 1e-9)));
+      String item = String
+          .format("%-45s%-25s%-25s%-25s", operation.name, cnt + "", totalInMs + "", avg);
+      LOGGER.info(item);
+    }
+    LOGGER.info(
+        "==========================================OPERATION HISTOGRAM====================================================");
+    String histogramHead = String.format("%-45s", "OPERATION");
+    for (int i = 0; i < BUCKET_SIZE; i++) {
+      histogramHead += String.format("%-8s", BUCKET_IN_MS[i] + "ms");
+    }
+    LOGGER.info(histogramHead);
+    for (Operation operation : Operation.values()) {
+      String item = String.format("%-45s", operation.getName());
+      long cnt = operationCnt[operation.ordinal()];
+      for (int i = 0; i < BUCKET_SIZE; i++) {
+        String avg = String
+            .format("%.2f", (operationHistogram[operation.ordinal()][i] / (cnt + 1e-9) * 100));
+        item += String.format("%-8s", avg + "%");
+      }
+      LOGGER.info(item);
+    }
+
+    LOGGER.info(
+        "=================================================================================================================");
+  }
+
+  class DisplayRunnable implements Runnable {
+
+    @Override
+    public void run() {
+      showMeasurements();
+    }
+  }
+
+  class QueueConsumerThread implements Runnable {
+
+    @Override
+    public void run() {
+      consumer();
+    }
+
+    private void consumer(){
+      int cnt = 0;
+      boolean allEmpty = false;
+      while (true) {
+        cnt++;
+        if (cnt > 2 * QUEUE_SIZE || allEmpty) {
+          try {
+            Thread.sleep(1000);
+            cnt = 0;
+            allEmpty = false;
+            continue;
+          } catch (InterruptedException e) {
+            return;
+          }
+        }
+        allEmpty = true;
+        for (Operation op : Operation.values()) {
+          int idx = op.ordinal();
+          Queue<Long> queue = operationLatenciesQueue[idx];
+          Long time = queue.poll();
+          if (time != null) {
+            operationLatencies[idx] += time;
+            operationCnt[idx]++;
+            operationHistogram[idx][calIndex(time)]++;
+            allEmpty = false;
+          }
+        }
+      }
+    }
+  }
+  private int calIndex(long x) {
+    x /= MS_TO_NANO;
+    for (int i = 0; i < MS_TO_NANO; i++) {
+      if (BUCKET_IN_MS[i] >= x) {
+        return i;
+      }
+    }
+    return BUCKET_SIZE - 1;
+  }
+
+}
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/MeasurementMBean.java b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/MeasurementMBean.java
new file mode 100644
index 0000000..4250f9c
--- /dev/null
+++ b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/MeasurementMBean.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.cost.statistic;
+
+public interface MeasurementMBean {
+
+  /**
+   * start display performance statistic every interval of displayIntervalInMs.
+   */
+  void startContinuousStatistics();
+
+  /**
+   * start display performance statistic after interval of displayIntervalInMs.
+   */
+  void startOneTimeStatistics();
+
+  /**
+   * stop display performance statistic.
+   */
+  void stopStatistic();
+
+  boolean isEnableStat();
+
+  void setEnableStat(boolean enableStat);
+
+  long getDisplayIntervalInMs();
+
+  void setDisplayIntervalInMs(long displayIntervalInMs);
+}
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/cost/stastic/Operation.java b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Operation.java
similarity index 97%
rename from iotdb/src/main/java/org/apache/iotdb/db/cost/stastic/Operation.java
rename to iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Operation.java
index d140fe9..4e5c363 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/cost/stastic/Operation.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Operation.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.cost.stastic;
+package org.apache.iotdb.db.cost.statistic;
 
 public enum Operation {
   EXECUTE_BATCH_SQL("EXECUTE_BATCH_SQL"),
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Test.java b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Test.java
new file mode 100644
index 0000000..2172a87
--- /dev/null
+++ b/iotdb/src/main/java/org/apache/iotdb/db/cost/statistic/Test.java
@@ -0,0 +1,35 @@
+package org.apache.iotdb.db.cost.statistic;
+
+public class Test {
+
+  public static void main(String[] args) {
+    Measurement.INSTANCE.addOperationLatency(Operation.EXECUTE_BATCH_SQL, System.nanoTime());
+    Measurement.INSTANCE.addOperationLatency(Operation.EXECUTE_BATCH_SQL, System.nanoTime()-8000000);
+
+    try {
+      Measurement.INSTANCE.start();
+      Measurement.INSTANCE.startContinuousStatistics();
+      Measurement.INSTANCE.addOperationLatency(Operation.EXECUTE_BATCH_SQL, System.nanoTime());
+      Measurement.INSTANCE.addOperationLatency(Operation.EXECUTE_BATCH_SQL, System.nanoTime()-8000000);
+      Thread.currentThread().sleep(2000);
+      Measurement.INSTANCE.stopStatistic();
+      Measurement.INSTANCE.stopStatistic();
+      Measurement.INSTANCE.stopStatistic();
+      System.out.println("After stopStatistic!");
+      Thread.currentThread().sleep(1000);
+      Measurement.INSTANCE.startContinuousStatistics();
+      System.out.println("RE start!");
+      Thread.currentThread().sleep(2000);
+      Measurement.INSTANCE.startContinuousStatistics();
+      System.out.println("RE start2!");
+      Thread.currentThread().sleep(2000);
+      Measurement.INSTANCE.stopStatistic();
+      System.out.println("After stopStatistic2!");
+      Measurement.INSTANCE.stop();
+
+    }
+    catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeManager.java b/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeManager.java
index 2adf3f6..49f8f2c 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeManager.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeManager.java
@@ -36,8 +36,8 @@ import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.conf.directories.Directories;
-import org.apache.iotdb.db.cost.stastic.Measurement;
-import org.apache.iotdb.db.cost.stastic.Operation;
+import org.apache.iotdb.db.cost.statistic.Measurement;
+import org.apache.iotdb.db.cost.statistic.Operation;
 import org.apache.iotdb.db.engine.Processor;
 import org.apache.iotdb.db.engine.bufferwrite.BufferWriteProcessor;
 import org.apache.iotdb.db.engine.memcontrol.BasicMemController;
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java b/iotdb/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
index 70dc42a..356fe74 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
@@ -21,8 +21,8 @@ package org.apache.iotdb.db.qp;
 import java.time.ZoneId;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.cost.stastic.Measurement;
-import org.apache.iotdb.db.cost.stastic.Operation;
+import org.apache.iotdb.db.cost.statistic.Measurement;
+import org.apache.iotdb.db.cost.statistic.Operation;
 import org.apache.iotdb.db.exception.ArgsErrorException;
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.qp.IllegalASTFormatException;
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/qp/executor/OverflowQPExecutor.java b/iotdb/src/main/java/org/apache/iotdb/db/qp/executor/OverflowQPExecutor.java
index 90b77e6..475fa3d 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/qp/executor/OverflowQPExecutor.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/qp/executor/OverflowQPExecutor.java
@@ -31,8 +31,8 @@ import org.apache.iotdb.db.auth.entity.PathPrivilege;
 import org.apache.iotdb.db.auth.entity.PrivilegeType;
 import org.apache.iotdb.db.auth.entity.Role;
 import org.apache.iotdb.db.auth.entity.User;
-import org.apache.iotdb.db.cost.stastic.Measurement;
-import org.apache.iotdb.db.cost.stastic.Operation;
+import org.apache.iotdb.db.cost.statistic.Measurement;
+import org.apache.iotdb.db.cost.statistic.Operation;
 import org.apache.iotdb.db.engine.filenode.FileNodeManager;
 import org.apache.iotdb.db.exception.ArgsErrorException;
 import org.apache.iotdb.db.exception.FileNodeManagerException;
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/service/IoTDB.java b/iotdb/src/main/java/org/apache/iotdb/db/service/IoTDB.java
index a7cf296..0d85814 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/service/IoTDB.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/service/IoTDB.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.db.concurrent.IoTDBDefaultThreadExceptionHandler;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.cost.statistic.Measurement;
 import org.apache.iotdb.db.engine.filenode.FileNodeManager;
 import org.apache.iotdb.db.engine.memcontrol.BasicMemController;
 import org.apache.iotdb.db.exception.FileNodeManagerException;
@@ -104,6 +105,7 @@ public class IoTDB implements IoTDBMBean {
     registerManager.register(StatMonitor.getInstance());
     registerManager.register(BasicMemController.getInstance());
     registerManager.register(SyncServiceManager.getInstance());
+    registerManager.register(Measurement.INSTANCE);
 
     JMXService.registerMBean(getInstance(), mbeanName);
 
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/service/ServiceType.java b/iotdb/src/main/java/org/apache/iotdb/db/service/ServiceType.java
index 4b396f2..c4cf00d 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/service/ServiceType.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/service/ServiceType.java
@@ -30,7 +30,8 @@ public enum ServiceType {
   JVM_MEM_CONTROL_SERVICE("Memory Controller", ""),
   AUTHORIZATION_SERVICE("Authorization ServerService", ""),
   FILE_READER_MANAGER_SERVICE("File reader manager ServerService", ""),
-  SYNC_SERVICE("SYNC ServerService", "");
+  SYNC_SERVICE("SYNC ServerService", ""),
+  PERFORMANCE_STATISTIC_SERVICE("PERFORMANCE_STATISTIC_SERVICE","PERFORMANCE_STATISTIC_SERVICE");
 
   private String name;
   private String jmxName;
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/iotdb/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
index 89f9265..5c12d59 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
@@ -35,8 +35,8 @@ import org.apache.iotdb.db.auth.authorizer.LocalFileAuthorizer;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.cost.stastic.Measurement;
-import org.apache.iotdb.db.cost.stastic.Operation;
+import org.apache.iotdb.db.cost.statistic.Measurement;
+import org.apache.iotdb.db.cost.statistic.Operation;
 import org.apache.iotdb.db.engine.filenode.FileNodeManager;
 import org.apache.iotdb.db.exception.ArgsErrorException;
 import org.apache.iotdb.db.exception.FileNodeManagerException;