/**********************************************************************************************
  File name     : ratelimit.h
  Module        : common
  Author        : 
  Copyright     : 
  Version       : 0.1
  Created on    : 2021-11-18
  Creator       : amir.liang
  Description   :
            以一定的速率执行入参函数， ratelimit(func()); 每次call这个调用，默认每5秒最多执行一次func()  
  Modify History:
  1. Date:        Author:         Modification:
************************************************************************************************/

#ifndef __RATELIMIT_H__
#define __RATELIMIT_H__

#include <stdint.h>
#include "htime.h"

/**
 * 参考linux kernel的 printk_ratelimited
 * 
 * 使用方法： 
 * 默认5秒只执行1次
 *  ratelimit(printf("test\n"));   
 *  * 
 * 设置成10秒可以执行30次
 * ratelimit2(10, 30, printf("test\n"));
 */

struct ratelimit_state {
    //下面是运行时信息
    uint32_t 			interval_ms;
    uint32_t            next_ms;
};

struct task_time_state
{
    uint32_t            task_start;
    uint32_t            task_print_time;
};

#define DEFAULT_RATELIMIT_INTERVAL     5
#define DEFAULT_RATELIMIT_BURST        1

//第2个版本，你也可以指定多少秒可以打印多少次
//ratelimit2(10, 30, printf("test\n"));

#define ratelimit2(_sec, _times, _action)      \
({                                          \
    static struct ratelimit_state _rs = {  	\
        _sec*1000/_times, 0			       	\
    };                                     	\
    uint32_t _now  = gettimeofday_ms();\
    if (_now >= _rs.next_ms){  			\
		_rs.next_ms = _now + _rs.interval_ms;    \
        _action;                             \
    }                                       \
})

//默认允许5秒打印1次log
//ratelimit(printf("test\n"));   
#define ratelimit(_action)  ratelimit2(DEFAULT_RATELIMIT_INTERVAL, 1, _action)


//尝试times，直到action结果等于ifequ，每次延时delayms
//do_retry2(action(), 10， 100， 0);  尝试10次action结果等于0时即退出，每次延时100ms
#define do_retry2(_action, _times, _delayms, _ifequ_break)\
({                                         \
    int32_t _t = _times;\
	while(_t-->0){\
		if (_ifequ_break)\
			break;\
		ratelimit2(1, 5, printf("waiting %dms:%s\n", _delayms, #_action));\
		usleep(_delayms*1000);\
	}\
})

//默认延时100ms, action结果等于0时退出
//do_retry(action(), 10);  尝试10次，直到action结果等于0时即退出，每次延时100ms
#define do_retry(_action, _times)  do_retry2(_action, _times, 100, ==0)



#define LOG_TIME2(_start_ts, _action) ({\
		uint64_t pre_ts = _start_ts == -1 ? gettimeofday_ms() : _start_ts;\
		_action;\
		printf("%lu %s take:%llums\n", pre_ts, #_action, gettimeofday_ms() - pre_ts);\
	})

/*
* 计算某个函数或操作所消耗的时间    
* _action, 可以是一个函数如: retalimit_delay()
* _action, 可以是一个字符串: "imin" 用于时间打印记录
*/
#define LOG_TIME(_action) LOG_TIME2(-1, _action)


void retalimit_test();

#endif //__RATELIMIT_H__

