xref: /minix/minix/kernel/system/do_sprofile.c (revision fb9c64b2)
1 /* The kernel call that is implemented in this file:
2  *   m_type:    SYS_SPROF
3  *
4  * The parameters for this kernel call are:
5  *	m_lsys_krn_sys_sprof.action	(start/stop profiling)
6  *	m_lsys_krn_sys_sprof.mem_size	(available memory for data)
7  *	m_lsys_krn_sys_sprof.freq	(requested sample frequency)
8  *	m_lsys_krn_sys_sprof.endpt	(endpoint of caller)
9  *	m_lsys_krn_sys_sprof.ctl_ptr	(location of info struct)
10  *	m_lsys_krn_sys_sprof.mem_ptr	(location of memory for data)
11  *	m_lsys_krn_sys_sprof.intr_type	(interrupt source: RTC/NMI)
12  *
13  * Changes:
14  *   14 Aug, 2006   Created (Rogier Meurs)
15  */
16 
17 #include "kernel/system.h"
18 #include "kernel/watchdog.h"
19 
20 #if SPROFILE
21 
22 /* user address to write info struct */
23 static vir_bytes sprof_info_addr_vir;
24 
25 static void clean_seen_flag(void)
26 {
27 	int i;
28 
29 	for (i = 0; i < NR_TASKS + NR_PROCS; i++)
30 		proc[i].p_misc_flags &= ~MF_SPROF_SEEN;
31 }
32 
33 /*===========================================================================*
34  *				do_sprofile				     *
35  *===========================================================================*/
36 int do_sprofile(struct proc * caller, message * m_ptr)
37 {
38   int proc_nr;
39   int err;
40 
41   switch(m_ptr->m_lsys_krn_sys_sprof.action) {
42 
43   case PROF_START:
44 	/* Starting profiling.
45 	 *
46 	 * Check if profiling is not already running.  Calculate physical
47 	 * addresses of user pointers.  Reset counters.  Start CMOS timer.
48 	 * Turn on profiling.
49 	 */
50 	if (sprofiling) {
51 		printf("SYSTEM: start s-profiling: already started\n");
52 		return EBUSY;
53 	}
54 
55 	/* Test endpoint number. */
56 	if(!isokendpt(m_ptr->m_lsys_krn_sys_sprof.endpt, &proc_nr))
57 		return EINVAL;
58 
59 	/* Set parameters for statistical profiler. */
60 	sprof_ep = m_ptr->m_lsys_krn_sys_sprof.endpt;
61 	sprof_info_addr_vir = m_ptr->m_lsys_krn_sys_sprof.ctl_ptr;
62 	sprof_data_addr_vir = m_ptr->m_lsys_krn_sys_sprof.mem_ptr;
63 
64 	sprof_info.mem_used = 0;
65 	sprof_info.total_samples = 0;
66 	sprof_info.idle_samples = 0;
67 	sprof_info.system_samples = 0;
68 	sprof_info.user_samples = 0;
69 
70 	sprof_mem_size =
71 		m_ptr->m_lsys_krn_sys_sprof.mem_size < SAMPLE_BUFFER_SIZE ?
72 		m_ptr->m_lsys_krn_sys_sprof.mem_size : SAMPLE_BUFFER_SIZE;
73 
74 	switch (sprofiling_type = m_ptr->m_lsys_krn_sys_sprof.intr_type) {
75 		case PROF_RTC:
76 			init_profile_clock(m_ptr->m_lsys_krn_sys_sprof.freq);
77 			break;
78 		case PROF_NMI:
79 			err = nmi_watchdog_start_profiling(
80 				m_ptr->m_lsys_krn_sys_sprof.freq);
81 			if (err)
82 				return err;
83 			break;
84 		default:
85 			printf("ERROR : unknown profiling interrupt type\n");
86 			return EINVAL;
87 	}
88 
89 	sprofiling = 1;
90 
91 	clean_seen_flag();
92 
93   	return OK;
94 
95   case PROF_STOP:
96 	/* Stopping profiling.
97 	 *
98 	 * Check if profiling is indeed running.  Turn off profiling.
99 	 * Stop CMOS timer.  Copy info struct to user process.
100 	 */
101 	if (!sprofiling) {
102 		printf("SYSTEM: stop s-profiling: not started\n");
103 		return EBUSY;
104 	}
105 
106 	sprofiling = 0;
107 
108 	switch (sprofiling_type) {
109 		case PROF_RTC:
110 			stop_profile_clock();
111 			break;
112 		case PROF_NMI:
113 			nmi_watchdog_stop_profiling();
114 			break;
115 	}
116 
117 	data_copy(KERNEL, (vir_bytes) &sprof_info,
118 		sprof_ep, sprof_info_addr_vir, sizeof(sprof_info));
119 	data_copy(KERNEL, (vir_bytes) sprof_sample_buffer,
120 		sprof_ep, sprof_data_addr_vir, sprof_info.mem_used);
121 
122 	clean_seen_flag();
123 
124   	return OK;
125 
126   default:
127 	return EINVAL;
128   }
129 }
130 
131 #endif /* SPROFILE */
132 
133