#ifndef __MEASURE_H
#define __MEASURE_H
#ifdef __KERNEL__
// OS-dependent definition
#define measure_gettimeofday(do) do_gettimeofday(do)
#define TIMEVAL struct timeval
// END OF OS-dependent definition
#endif

#if defined(CONFIG_RK) || defined(__RK__)
#include <rk/rk.h>
#endif

#define MEASURE_BEGIN 0
#define MEASURE_SLICE 1
#define MEASURE_END   2
#define MEASURE_INTERRUPT 3
#define MEASURE_IRQ 4
#define MEASURE_SOFTIRQ 5
#define MEASURE_SD 6
#define MEASURE_CS 7
#define MEASURE_DELAY 8
#define MEASURE_STACK 9

#define STACK_IN_KERNEL 0
#define STACK_IN_MODULE 1
#define STACK_LAST_ONE  2

typedef struct {
  unsigned int  pid;
  unsigned int  sysno;
  unsigned char flags;
  unsigned char subseq;
  unsigned char dummy;
  unsigned long long measure;
} MEASURE;

typedef struct {
  int (*reg)(int pid,int cmd,long data);
  int (*getinfo)(MEASURE *info);
  void (*add_entry)(int, unsigned char,int,unsigned char,unsigned int);
  void (*add_longentry)(int, unsigned char,int,unsigned char,long long);
  void (*begin_measure)(int);
  void (*end_measure)(void);
  void (*break_measure)(int);
  void (*irq_on)(int);
  void (*irq_off)(int);
  void (*softirq_on)(int);
  void (*softirq_off)(int);
  void (*schedule_on)(void);
  void (*schedule_off)(void);
  void (*cs_on)(void);
  void (*cs_off)(void);
  void (*new_slice)(int pid);
  void (*end_slice)(int pid);
  void (*clear_process)(int pid);
  void (*contextswap)(int pid);
  void (*newprocess)(int pid);
  void (*endprocess)(int pid);
  void (*syscall)(int pid, int no);
#if defined(CONFIG_RK) || defined(__RK__)
  void (*new_reserve)(void *cpu);
  void (*end_reserve)(void *cpu);
  void (*rsv_swapto)(rk_reserve_t rsv);
  void (*rsv_att_proc)(rk_reserve_t rsv, int pid);
  void (*rsv_det_proc)(rk_reserve_t rsv, int pid);
#endif
} MeasureOp;

extern MeasureOp *current_measure_hook;

#define MEASURE_MAX_ENTRY 1024*100
#define MEASURE_OFF            	0
#define MEASURE_ON               1
#define MEASURE_REGISTER_SYS     2
#define MEASURE_UNREGISTER_SYS   3
#define MEASURE_SET_BREAK        4
#define MEASURE_CLEAR_BREAK      5
#define MEASURE_THRESHOLD        6
#define MEASURE_SET_IRQ          7
#define MEASURE_CLEAR_IRQ        8
#define MEASURE_GET_IRQ          9
#define MEASURE_MONITOR_INTERRUPT      10
#define MEASURE_MONITOR_PAGEFAULT 11
#define MEASURE_MONITOR_SOFTIRQ 12
#define MEASURE_MONITOR_SCHEDULE 13
#define MEASURE_MONITOR_CS 14
#define MEASURE_MONITOR_CONTEXTSWAP 15
#define MEASURE_MONITOR_NEWPROCESS 16
#define MEASURE_MONITOR_ENDPROCESS 17


#define MEASURE_NEWPROCESS 		100
#define MEASURE_ENDPROCESS 		101
#define MEASURE_SYSCALL 			102
#define MEASURE_CONTEXTSWAP_TO 	103
#define MEASURE_USER_EVENT 		104

int sys_measure_register(int pid,int cmd,int data);
int sys_measure_getinfo(MEASURE *buf);


#ifdef __KERNEL__


extern int measure_sys_process;
extern MEASURE measure_array[MEASURE_MAX_ENTRY];
//extern char measure_sys[NR_syscalls];
extern int measure_on;
extern int measure_ptr;
extern int measure_all;
extern unsigned long long measure_lasttimestamp;
extern unsigned int measure_startirq;
extern unsigned long slice_seq;
extern int measure_lastsysno;
extern unsigned long measure_interrupt;
extern int measure_monitor_irq;
extern int measure_monitor_pagefault;

void measure_begin(int no);
void measure_end(void);
extern inline unsigned long long get_rdtsc(void)
{
  unsigned long long now;
  rdtscll(now);
  return now;
}
extern inline unsigned long long _rdtsc(void)
{
  unsigned long long data;
  unsigned long long *data_p = &data;
	__asm __volatile(
		"rdtsc"
		:"=a"(*(int *)(data_p)), "=d"(*(((int *)data_p)+1))
		:
		:"eax","edx");
	return data;
}


extern inline void measure_end_slice(int pid)
{
  if (current_measure_hook&&current_measure_hook->end_slice)
    current_measure_hook->end_slice(pid);
}

extern inline void measure_new_slice(int pid)
{
  if (current_measure_hook&&current_measure_hook->new_slice)
    current_measure_hook->new_slice(pid);
}

extern inline void measure_clear_process(int pid)
{
  if (current_measure_hook&&current_measure_hook->clear_process)
    current_measure_hook->clear_process(pid);
}




extern inline void measure_add_entry(int pid,unsigned char flags,int sysno,unsigned char subseq,unsigned int usec)
{
  if (current_measure_hook&&current_measure_hook->add_entry)
    current_measure_hook->add_entry(pid,flags,sysno,subseq,usec);
}

extern inline void measure_add_longentry(int pid,unsigned char flags, int sysno,unsigned char  subseq,long long usec)
{
  if (current_measure_hook&&current_measure_hook->add_longentry)
    current_measure_hook->add_longentry(pid,flags,sysno,subseq,usec);
}


extern inline void measure_break(int mark)
{
  if (current_measure_hook&&current_measure_hook->break_measure)
    current_measure_hook->break_measure(mark);
}

extern inline void measure_irq_on(int irq)
{
  if (current_measure_hook&&current_measure_hook->irq_on)
    current_measure_hook->irq_on(irq);
}

extern inline void measure_irq_off(int irq)
{
  if (current_measure_hook&&current_measure_hook->irq_off)
    current_measure_hook->irq_off(irq);
}

extern inline void measure_softirq_on(int intno)
{
  if (current_measure_hook&&current_measure_hook->softirq_on)
    return current_measure_hook->softirq_on(intno);
}

extern inline void measure_softirq_off(int no)
{
  if (current_measure_hook&&current_measure_hook->softirq_on)
    current_measure_hook->softirq_off(no);
}

extern inline void measure_schedule_on(void)
{
  if (current_measure_hook&&current_measure_hook->schedule_on)
    current_measure_hook->schedule_on();
}
extern inline void measure_newprocess(int newpid)
{
  if (current_measure_hook&&current_measure_hook->newprocess)
    current_measure_hook->newprocess(newpid);
}
extern inline void measure_endprocess(int pid)
{
  if (current_measure_hook&&current_measure_hook->endprocess)
    current_measure_hook->endprocess(pid);
}
extern inline void measure_contextswap(int newpid)
{
  if (current_measure_hook&&current_measure_hook->contextswap)
    current_measure_hook->contextswap(newpid);
}
extern inline void measure_schedule_off(void)
{
  if (current_measure_hook&&current_measure_hook->schedule_off)
    current_measure_hook->schedule_off();
}

extern inline void measure_cs_on(void)
{
  if (current_measure_hook&&current_measure_hook->cs_on)
    current_measure_hook->cs_on();
}

extern inline void measure_cs_off(void)
{
  if (current_measure_hook&&current_measure_hook->cs_off)
    current_measure_hook->cs_off();
}

#ifdef CONFIG_RK
extern inline void measure_newreserve(void *cpu)
{
  if (current_measure_hook&&current_measure_hook->new_reserve)
    current_measure_hook->new_reserve(cpu);
}

extern inline void measure_endreserve(void *cpu)
{
  if (current_measure_hook&&current_measure_hook->end_reserve)
    current_measure_hook->end_reserve(cpu);
}

extern inline void measure_reserve_swapto(rk_reserve_t cpu)
{
  if (current_measure_hook&&current_measure_hook->rsv_swapto)
    current_measure_hook->rsv_swapto(cpu);
}

extern inline void measure_reserv_attach_process(rk_reserve_t rsv, int pid)
{
  if (current_measure_hook&&current_measure_hook->rsv_att_proc)
    current_measure_hook->rsv_att_proc(rsv,pid);
}

extern inline void measure_reserv_detach_process(rk_reserve_t rsv, int pid)
{
  if (current_measure_hook&&current_measure_hook->rsv_det_proc)
    current_measure_hook->rsv_det_proc(rsv,pid);
}

#endif /* CONFIG_RK */
#endif /* __KERNEL__ */
#endif /* __MEASURE_H */
