public Summary summarize() {
        // ignore unused timers
        List<Summary> summaries = Arrays.stream(timerTable)
                .map(Timer::summarize)
                .filter(s -> s.getTaskCount() > 0)
                .collect(Collectors.toList());

        // summarize data
        long totalTaskTimeMillis = 0L;
        long maxTaskTimeMillis = DEFAULT_TIME_MILLS;
        long minTaskTimeMillis = DEFAULT_TIME_MILLS;
        long taskCount = 0L;
        for (Summary summary : summaries) {
            if (taskCount > 0) {
                maxTaskTimeMillis = Math.max(maxTaskTimeMillis, summary.getMaxTaskTimeMillis());
                minTaskTimeMillis = Math.min(minTaskTimeMillis, summary.getMinTaskTimeMillis());
            } else {
                maxTaskTimeMillis = summary.getMaxTaskTimeMillis();
                minTaskTimeMillis = summary.getMinTaskTimeMillis();
            }
            totalTaskTimeMillis += summary.getTotalTaskTimeMillis();
            taskCount += summary.getTaskCount();
        }
        return new Summary(totalTaskTimeMillis, maxTaskTimeMillis, minTaskTimeMillis, taskCount);
    }
@Test
    public void testSummarize() {
        ExtensibleThreadPoolExecutor executor = new ExtensibleThreadPoolExecutor(
                "test", new DefaultThreadPoolPluginManager(),
                3, 3, 1000L, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<>(1), Thread::new, new ThreadPoolExecutor.DiscardPolicy());

        TaskTimeRecordPlugin plugin = new TaskTimeRecordPlugin(3);
        executor.register(plugin);
        executor.submit(() -> ThreadUtil.sleep(1000L));
        executor.submit(() -> ThreadUtil.sleep(3000L));
        executor.submit(() -> ThreadUtil.sleep(2000L));
        executor.submit(() -> ThreadUtil.sleep(2000L));

        // waiting for shutdown
        executor.shutdown();
        while (!executor.isTerminated()) {
        }
        TaskTimeRecordPlugin.Summary summary = plugin.summarize();
        Assert.assertTrue(summary.getMinTaskTimeMillis() > 0L);
        Assert.assertTrue(summary.getMaxTaskTimeMillis() > 0L);
        Assert.assertTrue(summary.getAvgTaskTimeMillis() > 0L);
        Assert.assertTrue(summary.getTotalTaskTimeMillis() > 0L);
        // Assert.assertTrue(testInDeviation(summary.getMinTaskTimeMillis(), 1000L, 300L));
        // Assert.assertTrue(testInDeviation(summary.getMaxTaskTimeMillis(), 3000L, 300L));
        // Assert.assertTrue(testInDeviation(summary.getAvgTaskTimeMillis(), 2000L, 300L));
        // Assert.assertTrue(testInDeviation(summary.getTotalTaskTimeMillis(), 8000L, 300L));
    }