#ifndef HEADER_LIBFLOW_H #define HEADER_LIBFLOW_H #include #include struct flow; typedef int (*flow_func_flush_chunk_t)(const struct flow *fw, int fd); struct flow { /* Total number of bytes to be processed. */ uint64_t total_size; /* Total number of bytes already processed. */ uint64_t total_processed; /* If true, show progress. */ int progress; /* Block size in bytes. */ int block_size; /* Delay intended between measurements in milliseconds. */ unsigned int delay_ms; /* Increment to apply to @blocks_per_delay. */ int64_t step; /* Blocks to process before measurement. */ int64_t blocks_per_delay; /* Maximum processing rate in bytes per second. */ double max_process_rate; /* Number of measured blocks. */ uint64_t measured_blocks; /* Measured time. */ uint64_t measured_time_ms; /* State. */ enum {FW_INC, FW_DEC, FW_SEARCH, FW_STEADY} state; /* Number of characters to erase before printing out progress. */ int erase; /* * Methods */ flow_func_flush_chunk_t func_flush_chunk; /* * Initialized while measuring */ /* Number of blocks processed since last measurement. */ int64_t processed_blocks; /* * Accumulated delay before @processed_blocks reaches @blocks_per_delay * in microseconds. */ uint64_t acc_delay_us; /* Range of blocks_per_delay while in FW_SEARCH state. */ int64_t bpd1, bpd2; /* Time measurements. */ struct timeval t1; }; /* If @max_process_rate <= 0, the maximum processing rate is infinity. * The unit of @max_process_rate is KB per second. */ void init_flow(struct flow *fw, uint64_t total_size, long max_process_rate, int progress, flow_func_flush_chunk_t func_flush_chunk); void start_measurement(struct flow *fw); int measure(int fd, struct flow *fw, long processed); int end_measurement(int fd, struct flow *fw); static inline int has_enough_measurements(const struct flow *fw) { return fw->measured_time_ms > fw->delay_ms; } static inline double get_avg_speed_given_time(struct flow *fw, uint64_t total_time_ms) { return (double)(fw->measured_blocks * fw->block_size * 1000) / total_time_ms; } /* Average writing speed in byte/s. */ static inline double get_avg_speed(struct flow *fw) { return get_avg_speed_given_time(fw, fw->measured_time_ms); } static inline uint64_t get_rem_chunk_size(struct flow *fw) { assert(fw->blocks_per_delay > fw->processed_blocks); return (fw->blocks_per_delay - fw->processed_blocks) * fw->block_size; } struct dynamic_buffer { char *buf; size_t len; bool max_buf; char backup_buf[1 << 21]; /* 2MB */ }; static inline void dbuf_init(struct dynamic_buffer *dbuf) { dbuf->buf = dbuf->backup_buf; dbuf->len = sizeof(dbuf->backup_buf); dbuf->max_buf = false; } void dbuf_free(struct dynamic_buffer *dbuf); /* * Although the returned buffer may be smaller than @size, * this function never returns NULL. */ char *dbuf_get_buf(struct dynamic_buffer *dbuf, size_t size); static inline size_t dbuf_get_len(const struct dynamic_buffer *dbuf) { return dbuf->len; } #endif /* HEADER_LIBFLOW_H */