All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joyqueue.toolkit.stat.TPStatBuffer Maven / Gradle / Ivy

/**
 * Copyright 2019 The JoyQueue Authors.
 *
 * Licensed 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.joyqueue.toolkit.stat;

import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;

/**
 * TP性能统计缓冲器,用于计算
 */
public class TPStatBuffer implements Serializable {
    // 默认矩阵长度,2的指数,便于取余数
    protected static final int LENGTH = 256;
    // 矩阵,最多存放length*length-1
    protected AtomicReferenceArray timer;
    // 超过maxTime的数据存储在这俩
    protected AtomicReference> outstrip;
    // 成功处理的记录条数
    protected AtomicLong recordTotal = new AtomicLong(0);
    // 成功调用次数
    protected AtomicLong successTotal = new AtomicLong(0);
    // 失败调用次数
    protected AtomicLong errorTotal = new AtomicLong(0);
    // 数据大小
    protected AtomicLong sizeTotal = new AtomicLong(0);
    // 总时间
    protected AtomicLong timeTotal = new AtomicLong(0);
    // 最大时间
    protected int maxTime;
    // 矩阵的长度
    protected int length;
    // 2的指数
    protected int exponent;

    public TPStatBuffer() {
        this(LENGTH);
    }

    public TPStatBuffer(int length) {
        if (length < 1) {
            throw new IllegalArgumentException("length must be greater than 0");
        }

        // 容量是2的指数
        int cap = 1;
        int exponent = 0;
        while (length > cap) {
            cap <<= 1;
            exponent++;
        }
        this.length = cap;
        this.exponent = exponent;
        this.timer = new AtomicReferenceArray(cap);
        this.outstrip = new AtomicReference>();
        this.maxTime = cap * cap - 1;
    }

    /**
     * 清理
     */
    public void clear() {
        timer = new AtomicReferenceArray(length);
        successTotal.set(0);
        errorTotal.set(0);
        sizeTotal.set(0);
        timeTotal.set(0);
        // 如果有数据超过了maxTime,则保留map数据,避免创建对象开销
        ConcurrentMap exceeds = outstrip.get();
        if (exceeds != null) {
            exceeds.clear();
        }
    }

    /**
     * 成功调用,批量增加统计信息,每次调用时间一样.
     *
     * @param time    单次调用时间
     * @param count   调用次数
     * @param records 总共记录条数
     * @param size    总共数据包大小
     */
    public void success(final int time, final int count, final int records, final long size) {
        if (time < 0 || count <= 0) {
            // 做性能统计时间不可能为负数
            return;
        }
        successTotal.addAndGet(count);
        if (records > 0) {
            recordTotal.addAndGet(records);
        }
        if (size > 0) {
            sizeTotal.addAndGet(size);
        }
        if (time > 0) {
            timeTotal.addAndGet(time * count);
        }
        int maxIndex = length - 1;

        if (time > maxTime) {
            // 超过最大时间,矩阵不能存储,采用MAP存储
            ConcurrentMap exceeds = outstrip.get();
            if (exceeds == null) {
                // 按时间排序
                exceeds = new ConcurrentSkipListMap();
                if (!outstrip.compareAndSet(null, exceeds)) {
                    exceeds = outstrip.get();
                }
            }
            AtomicLong counts = exceeds.get(time);
            if (counts == null) {
                counts = new AtomicLong();
                AtomicLong old = exceeds.putIfAbsent(time, counts);
                if (old != null) {
                    counts = old;
                }
            }
            counts.addAndGet(count);
        } else {
            int i = time >> exponent;
            int j = time & maxIndex;
            AtomicLongArray v = timer.get(i);
            if (v == null) {
                v = new AtomicLongArray(length);
                if (!timer.compareAndSet(i, null, v)) {
                    v = timer.get(i);
                }
            }
            v.addAndGet(j, count);
        }
    }

    /**
     * 单词调用成功
     *
     * @param records 记录条数
     * @param size    数据包大小
     * @param time    调用时间
     */
    public void success(final int records, final long size, final int time) {
        success(time, 1, records, size);
    }

    /**
     * 出错,增加TP计数
     */
    public void error() {
        errorTotal.incrementAndGet();
    }

    /**
     * 出错,增加TP计数
     *
     * @param count 调用次数
     */
    public void error(final int count) {
        errorTotal.addAndGet(count);
    }

    /**
     * 获取性能统计
     *
     * @return 性能统计
     */
    public TPStat getTPStat() {
        TPStat stat = new TPStat();
        stat.setSuccess(successTotal.get());
        stat.setError(errorTotal.get());
        stat.setCount(recordTotal.get());
        stat.setTime(timeTotal.get());
        stat.setSize(sizeTotal.get());

        if (stat.getSuccess() <= 0) {
            return stat;
        }

        int min = -1;
        int max = -1;
        // 计算排序位置
        int tp999 = (int) Math.floor(stat.getSuccess() * 99.9 / 100);
        int tp99 = (int) Math.floor(stat.getSuccess() * 99.0 / 100);
        int tp90 = (int) Math.floor(stat.getSuccess() * 90.0 / 100);
        int tp50 = (int) Math.floor(stat.getSuccess() * 50.0 / 100);

        long count;
        long prev = 0;
        long pos = 0;
        int time;
        AtomicLongArray v;
        // 递增遍历数组
        for (int i = 0; i < length; i++) {
            v = timer.get(i);
            if (v != null) {
                for (int j = 0; j < length; j++) {
                    // 获取该时间的数量
                    count = v.get(j);
                    if (count > 0) {
                        time = i * length + j;
                        // 当前排序位置
                        pos = prev + count;
                        if (min == -1) {
                            min = time;
                        }
                        if (max == -1 || time > max) {
                            max = time;
                        }
                        if (prev < tp50 && pos >= tp50) {
                            stat.setTp50(time);
                        }
                        if (prev < tp90 && pos >= tp90) {
                            stat.setTp90(time);
                        }
                        if (prev < tp99 && pos >= tp99) {
                            stat.setTp99(time);
                        }
                        if (prev < tp999 && pos >= tp999) {
                            stat.setTp999(time);
                        }
                        prev = pos;
                    }
                }
            }
        }
        // 遍历超过最大时间的数据
        ConcurrentMap exceeds = outstrip.get();
        if (exceeds != null) {
            for (Map.Entry entry : exceeds.entrySet()) {
                time = entry.getKey();
                pos = prev + entry.getValue().get();
                if (min == -1) {
                    min = time;
                }
                if (max == -1 || time > max) {
                    max = time;
                }
                if (prev < tp50 && pos >= tp50) {
                    stat.setTp50(time);
                }
                if (prev < tp90 && pos >= tp90) {
                    stat.setTp90(time);
                }
                if (prev < tp99 && pos >= tp99) {
                    stat.setTp99(time);
                }
                if (prev < tp999 && pos >= tp999) {
                    stat.setTp999(time);
                }
                prev = pos;
            }
        }

        stat.setMin(min);
        stat.setMax(max);
        return stat;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy