public EBPFProfilingAnalyzation analyze(List<String> scheduleIdList,
                                            List<EBPFProfilingAnalyzeTimeRange> ranges,
                                            EBPFProfilingAnalyzeAggregateType aggregateType) throws IOException {
        EBPFProfilingAnalyzation analyzation = new EBPFProfilingAnalyzation();

        // query data
        long queryDataMaxTimestamp = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(maxQueryTimeoutInSecond);
        final Stream<EBPFProfilingStack> stackStream = buildTimeRanges(ranges).parallelStream().map(r -> {
            try {
                return fetchDataThreadPool.submit(() -> getDataDAO().queryData(scheduleIdList, r.getMinTime(), r.getMaxTime()))
                        .get(queryDataMaxTimestamp - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                log.warn(e.getMessage(), e);
                return Collections.<EBPFProfilingDataRecord>emptyList();
            }
        }).flatMap(Collection::stream).map(e -> {
            try {
                return EBPFProfilingStack.deserialize(e, aggregateType);
            } catch (Exception ex) {
                log.warn("could not deserialize the stack", ex);
                return null;
            }
        }).filter(Objects::nonNull).distinct();

        // analyze tree
        generateTrees(analyzation, stackStream);

        return analyzation;
    }
@Test
    public void testAnalyze() throws IOException {
        EBPFProfilingAnalyzerHolder holder = loadYaml("ebpf-profiling-data.yml", EBPFProfilingAnalyzerHolder.class);

        for (int c = 0; c < holder.getList().size(); c++) {
            try {
                holder.getList().get(c).analyzeAssert();
            } catch (Error e) {
                throw new AssertionError("validate case " + c + " failure", e);
            }
        }
    }