/*
 * (C) Copyright Fuji Xerox Co., Ltd. All rights are reserved.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * 2019/05/29	nobuo.iwata@fujixerox.co.jp
 */

#ifndef __FXLSM_PROF_H
#define __FXLSM_PROF_H

#ifdef FXLSM_LIST_USER
#else
#include <linux/sched.h>
#endif /* !FXLSM_LIST_USER */

#ifdef FXLSM_USE_PROF_TIME

struct fxlsm_prof_time {
	unsigned long long time;
	unsigned long count;
	unsigned long long average;
};

#define FXLSM_PROF_TIME_ID_VOID		-1
#define FXLSM_PROF_TIME_OFF_LIST	0
#define FXLSM_PROF_TIME_ID_SEQ_HIT	(FXLSM_PROF_TIME_OFF_LIST + 0)
#define FXLSM_PROF_TIME_ID_SEQ_MIS	(FXLSM_PROF_TIME_OFF_LIST + 1)
#define FXLSM_PROF_TIME_ID_SEQ2_HIT	(FXLSM_PROF_TIME_OFF_LIST + 2)
#define FXLSM_PROF_TIME_ID_SEQ2_MIS	(FXLSM_PROF_TIME_OFF_LIST + 3)
#define FXLSM_PROF_TIME_ID_NSEQ_HIT	(FXLSM_PROF_TIME_OFF_LIST + 4)
#define FXLSM_PROF_TIME_ID_NSEQ_MIS	(FXLSM_PROF_TIME_OFF_LIST + 5)
#define FXLSM_PROF_TIME_ID_NSEQ2_HIT	(FXLSM_PROF_TIME_OFF_LIST + 6)
#define FXLSM_PROF_TIME_ID_NSEQ2_MIS	(FXLSM_PROF_TIME_OFF_LIST + 7)
#define FXLSM_PROF_TIME_ID_CAPF_HIT	(FXLSM_PROF_TIME_OFF_LIST + 8)
#define FXLSM_PROF_TIME_ID_CAPF_MIS	(FXLSM_PROF_TIME_OFF_LIST + 9)
#define FXLSM_PROF_TIME_ID_COMM_HIT	(FXLSM_PROF_TIME_OFF_LIST + 10)
#define FXLSM_PROF_TIME_ID_COMM_MIS	(FXLSM_PROF_TIME_OFF_LIST + 11)
#define FXLSM_PROF_TIME_ID_COMM2_HIT	(FXLSM_PROF_TIME_OFF_LIST + 12)
#define FXLSM_PROF_TIME_ID_COMM2_MIS	(FXLSM_PROF_TIME_OFF_LIST + 13)
#define FXLSM_PROF_TIME_ID_CAPC_HIT	(FXLSM_PROF_TIME_OFF_LIST + 14)
#define FXLSM_PROF_TIME_ID_CAPC_MIS	(FXLSM_PROF_TIME_OFF_LIST + 15)
#define FXLSM_PROF_TIME_ID_LD_HIT	(FXLSM_PROF_TIME_OFF_LIST + 16)
#define FXLSM_PROF_TIME_ID_LD_MIS	(FXLSM_PROF_TIME_OFF_LIST + 17)
#define FXLSM_PROF_TIME_ID_LD2_HIT	(FXLSM_PROF_TIME_OFF_LIST + 18)
#define FXLSM_PROF_TIME_ID_LD2_MIS	(FXLSM_PROF_TIME_OFF_LIST + 19)
#define FXLSM_PROF_TIME_ID_FILES_HIT	(FXLSM_PROF_TIME_OFF_LIST + 20)
#define FXLSM_PROF_TIME_ID_FILES_MIS	(FXLSM_PROF_TIME_OFF_LIST + 21)
#define FXLSM_PROF_TIME_ID_COMMS_HIT	(FXLSM_PROF_TIME_OFF_LIST + 22)
#define FXLSM_PROF_TIME_ID_COMMS_MIS	(FXLSM_PROF_TIME_OFF_LIST + 23)
#define FXLSM_PROF_TIME_ID_LDS_HIT	(FXLSM_PROF_TIME_OFF_LIST + 24)
#define FXLSM_PROF_TIME_ID_LDS_MIS	(FXLSM_PROF_TIME_OFF_LIST + 25)
#define FXLSM_PROF_TIME_NUM_LIST 	26
#define FXLSM_PROF_TIME_OFF_OPS	FXLSM_PROF_TIME_NUM_LIST
#define FXLSM_PROF_TIME_ID_FILE_OPEN	(FXLSM_PROF_TIME_OFF_OPS + 0)
#define FXLSM_PROF_TIME_ID_PATH_UNLINK	(FXLSM_PROF_TIME_OFF_OPS + 1)
#define FXLSM_PROF_TIME_ID_PATH_MKDIR	(FXLSM_PROF_TIME_OFF_OPS + 2)
#define FXLSM_PROF_TIME_ID_PATH_RMDIR	(FXLSM_PROF_TIME_OFF_OPS + 3)
#define FXLSM_PROF_TIME_ID_PATH_MKNOD	(FXLSM_PROF_TIME_OFF_OPS + 4)
#define FXLSM_PROF_TIME_ID_PATH_SYMLINK	(FXLSM_PROF_TIME_OFF_OPS + 5)
#define FXLSM_PROF_TIME_ID_PATH_LINK	(FXLSM_PROF_TIME_OFF_OPS + 6)
#define FXLSM_PROF_TIME_ID_PATH_RENAME	(FXLSM_PROF_TIME_OFF_OPS + 7)
#define FXLSM_PROF_TIME_ID_PATH_CHMOD	(FXLSM_PROF_TIME_OFF_OPS + 8)
#define FXLSM_PROF_TIME_ID_PATH_CHOWN	(FXLSM_PROF_TIME_OFF_OPS + 9)
#define FXLSM_PROF_TIME_ID_PATH_CHROOT	(FXLSM_PROF_TIME_OFF_OPS + 10)
#define FXLSM_PROF_TIME_ID_PATH_TRUNC	(FXLSM_PROF_TIME_OFF_OPS + 11)
#define FXLSM_PROF_TIME_ID_FILES_OK	(FXLSM_PROF_TIME_OFF_OPS + 12)
#define FXLSM_PROF_TIME_ID_FILES_ERR	(FXLSM_PROF_TIME_OFF_OPS + 13)
#define FXLSM_PROF_TIME_ID_COMMS_OK	(FXLSM_PROF_TIME_OFF_OPS + 14)
#define FXLSM_PROF_TIME_ID_COMMS_ERR	(FXLSM_PROF_TIME_OFF_OPS + 15)
#define FXLSM_PROF_TIME_ID_LDS_OK	(FXLSM_PROF_TIME_OFF_OPS + 16)
#define FXLSM_PROF_TIME_ID_LDS_ERR	(FXLSM_PROF_TIME_OFF_OPS + 17)
#define FXLSM_PROF_TIME_ID_CRMX		(FXLSM_PROF_TIME_OFF_OPS + 18)
#define FXLSM_PROF_TIME_ID_FILES_COMMS	(FXLSM_PROF_TIME_OFF_OPS + 19)
#define FXLSM_PROF_TIME_ID_LDS		(FXLSM_PROF_TIME_OFF_OPS + 20)
#define FXLSM_PROF_TIME_NUM_OPS		21
#define FXLSM_PROF_TIME_NUM \
		(FXLSM_PROF_TIME_NUM_LIST + FXLSM_PROF_TIME_NUM_OPS)

struct fxlsm_prof_time_id {
	int id;
	const char *name;
};

#define FXLSM_PROF_TIME_ID(__id, __name) \
		{ .id = FXLSM_PROF_TIME_ID_ ## __id, .name = __name }

#define FXLSM_PROF_TIME_ID_FOR_EACH(time_ids, p) \
		for (p = time_ids; (p)->id >= 0; p++)

void fxlsm_prof_time_add(int id, ktime_t time);
void fxlsm_prof_time_average(struct fxlsm_prof_time *p);
void fxlsm_prof_time_read(int id, struct fxlsm_prof_time *prof);
void fxlsm_prof_time_marge(
		struct fxlsm_prof_time *res,
		struct fxlsm_prof_time *p1, struct fxlsm_prof_time *p2,
		int *rate);
unsigned long long fxlsm_prof_time_running(void);
void fxlsm_prof_time_reset(void);

#define FXLSM_PROF_TIME(t) ktime_t t
#define FXLSM_PROF_TIME_START(t) t = ktime_get()
#define FXLSM_PROF_TIME_END_ONE(t, id) \
		fxlsm_prof_time_add(id, ktime_sub(ktime_get(), t))
#define FXLSM_PROF_TIME_END(t, cond, hit, mis) \
		if (cond) \
			fxlsm_prof_time_add(hit, ktime_sub(ktime_get(), t)); \
		else \
			fxlsm_prof_time_add(mis, ktime_sub(ktime_get(), t))
#define FXLSM_PROF_TIME_DEF(name) \
		struct fxlsm_prof_time name = { .time = 0, .count = 0}

#else /* FXLSM_USE_PROF_TIME */

#define FXLSM_PROF_TIME(t)
#define FXLSM_PROF_TIME_START(t) do {} while (0)
#define FXLSM_PROF_TIME_END_ONE(t, id) do {} while (0)
#define FXLSM_PROF_TIME_END(t, cond, hit, mis) do {} while (0)
#define FXLSM_PROF_TIME_DEF(name)

#endif /* !FXLSM_USE_PROF_TIME */

#ifdef FXLSM_USE_PROF_MEM

struct fxlsm_prof_mem {
	unsigned long bytes;
	unsigned long blocks;
};

#define FXLSM_PROF_MEM_ID_SEQ		0
#define FXLSM_PROF_MEM_ID_SEQ2		1
#define FXLSM_PROF_MEM_ID_NSEQ		2
#define FXLSM_PROF_MEM_ID_NSEQ2		3
#define FXLSM_PROF_MEM_ID_CAPF		4
#define FXLSM_PROF_MEM_ID_COMM		5
#define FXLSM_PROF_MEM_ID_COMM2		6
#define FXLSM_PROF_MEM_ID_CAPC		7
#define FXLSM_PROF_MEM_ID_LD		8
#define FXLSM_PROF_MEM_ID_LD2		9
#define FXLSM_PROF_MEM_ID_EVENTS	10
#define FXLSM_PROF_MEM_NUM		11

void fxlsm_prof_mem_add(int id, unsigned long bytes);
void fxlsm_prof_mem_sub(int id, unsigned long bytes);
const char *fxlsm_prof_mem_name(int id);
void fxlsm_prof_mem_read(int id, struct fxlsm_prof_mem *prof);
void fxlsm_prof_mem_total(struct fxlsm_prof_mem *prof);

#define FXLSM_PROF_MEM_ADD(bytes, id) \
		fxlsm_prof_mem_add(id, bytes)
#define FXLSM_PROF_MEM_SUB(bytes, id) \
		fxlsm_prof_mem_sub(id, bytes)
#define FXLSM_PROF_MEM_NAME(id) \
		fxlsm_prof_mem_name(id)
#define FXLSM_PROF_MEM_READ(prof, id) \
		fxlsm_prof_mem_read(id, prof)
#define FXLSM_PROF_MEM_TOTAL(prof) \
		fxlsm_prof_mem_total(prof)

#else /* FXLSM_USE_PROF_MEM */

#define FXLSM_PROF_MEM_ADD(bytes, id) do {} while (0)
#define FXLSM_PROF_MEM_SUB(bytes, id) do {} while (0)
#define FXLSM_PROF_MEM_NAME(id) do {} while (0)
#define FXLSM_PROF_MEM_READ(prof, id) do {} while (0)
#define FXLSM_PROF_MEM_TOTAL(prof) do {} while (0)

#endif /* !FXLSM_USE_PROF_MEM */

void fxlsm_prof_init(void);

#endif /* !__FXLSM_PROF_H */
