perfmon.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file contains the code to configure and utilize the ppc64 pmc hardware
  3.  * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
  4.  */
  5. #include <asm/proc_fs.h>
  6. #include <asm/paca.h>
  7. #include <asm/iSeries/ItLpPaca.h>
  8. #include <asm/iSeries/ItLpQueue.h>
  9. #include <asm/processor.h>
  10. #include <linux/proc_fs.h>
  11. #include <linux/spinlock.h>
  12. #include <asm/pmc.h>
  13. #include <asm/uaccess.h>
  14. #include <asm/naca.h>
  15. #include <asm/perfmon.h>
  16. extern char _stext[], _etext[], _end[];
  17. struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, PMC_STATE_INITIAL};
  18. int alloc_perf_buffer(int size);
  19. int free_perf_buffer(void);
  20. int clear_buffers(void);
  21. void pmc_stop(void *data);
  22. void pmc_start(void *data);
  23. void pmc_touch_bolted(void *data);
  24. void dump_pmc_struct(struct perfmon_struct *perfdata);
  25. void dump_hardware_pmc_struct(void *perfdata);
  26. int  decr_profile(struct perfmon_struct *perfdata);
  27. int  pmc_profile(struct perfmon_struct *perfdata);
  28. int  pmc_set_general(struct perfmon_struct *perfdata);
  29. int  pmc_set_user_general(struct perfmon_struct *perfdata);
  30. void pmc_configure(void *data);
  31. asmlinkage int
  32. sys_perfmonctl (int cmd, void *data) 
  33. struct perfmon_struct *pdata;
  34. int err;
  35. printk("sys_perfmonctl: cmd = 0x%xn", cmd); 
  36. pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
  37. err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
  38. switch(cmd) {
  39. case PMC_OP_ALLOC:
  40. alloc_perf_buffer(0); 
  41. break;
  42. case PMC_OP_FREE:
  43. free_perf_buffer(); 
  44. break;
  45. case PMC_OP_CLEAR:
  46. clear_buffers();
  47. break;
  48. case PMC_OP_DUMP:
  49. dump_pmc_struct(pdata);
  50. copy_to_user(data, pdata, sizeof(struct perfmon_struct));
  51. break;
  52. case PMC_OP_DUMP_HARDWARE:
  53. dump_hardware_pmc_struct(pdata);
  54. smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
  55. break;
  56. case PMC_OP_DECR_PROFILE: /* NIA time sampling */
  57. decr_profile(pdata); 
  58. break;
  59. case PMC_OP_PMC_PROFILE:
  60. pmc_profile(pdata); 
  61. break;
  62. case PMC_OP_SET:
  63. pmc_set_general(pdata); 
  64. break;
  65. case PMC_OP_SET_USER:
  66. pmc_set_user_general(pdata); 
  67. break;
  68. default:
  69. printk("Perfmon: Unknown operationn");
  70. break;
  71. }
  72. kfree(pdata); 
  73. return 0;
  74. }
  75. int alloc_perf_buffer(int size) 
  76. {
  77. int i;
  78. printk("Perfmon: allocate buffern");
  79. if(perfmon_base.state == PMC_STATE_INITIAL) {
  80. perfmon_base.profile_length = (((unsigned long) &_etext - 
  81.    (unsigned long) &_stext) >> 2) * sizeof(int);
  82. perfmon_base.profile_buffer = (unsigned long)btmalloc(perfmon_base.profile_length);
  83. perfmon_base.trace_length = 1024*1024*16;
  84. perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
  85. if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {
  86. memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
  87. printk("Profile buffer created at address 0x%lx of length 0x%lxn",
  88.        perfmon_base.profile_buffer, perfmon_base.profile_length); 
  89. } else {
  90. printk("Profile buffer creation failedn");
  91. return 0;
  92. }
  93. /* Fault in the first bolted segment - it then remains in the stab for all time */
  94. pmc_touch_bolted(NULL); 
  95. smp_call_function(pmc_touch_bolted, (void *)NULL, 0, 1);
  96. for (i=0; i<MAX_PACAS; ++i) {
  97. paca[i].prof_shift = 2;
  98. paca[i].prof_len = perfmon_base.profile_length;
  99. paca[i].prof_buffer = (unsigned *)(perfmon_base.profile_buffer);
  100. paca[i].prof_stext = (unsigned *)&_stext;
  101. paca[i].prof_etext = (unsigned *)&_etext;
  102. mb();
  103. perfmon_base.state = PMC_STATE_READY; 
  104. }
  105. return 0;
  106. }
  107. int free_perf_buffer() 
  108. {
  109. printk("Perfmon: free buffern");
  110. if(perfmon_base.state == PMC_STATE_INITIAL) {
  111. printk("Perfmon: free buffer failed - no buffer was allocated.n"); 
  112. return -1;
  113. }
  114. btfree((void *)perfmon_base.profile_buffer); 
  115. btfree((void *)perfmon_base.trace_buffer); 
  116. perfmon_base.profile_length = 0;
  117. perfmon_base.profile_buffer = 0;
  118. perfmon_base.trace_buffer   = 0;
  119. perfmon_base.trace_length   = 0;
  120. perfmon_base.trace_end      = 0;
  121. perfmon_base.state = PMC_STATE_INITIAL; 
  122. return(0); 
  123. }
  124. int clear_buffers() 
  125. {
  126. if(perfmon_base.state == PMC_STATE_INITIAL) {
  127. printk("Perfmon: clear buffer failed - no buffer was allocated.n"); 
  128. return -1;
  129. }
  130. printk("Perfmon: clear buffern");
  131. /* Stop counters on all processors -- blocking */
  132. pmc_stop(NULL); 
  133. smp_call_function(pmc_stop, (void *)NULL, 0, 1);
  134. /* Clear the buffers */
  135. memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
  136. memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);
  137. /* Reset the trace buffer point */
  138. perfmon_base.trace_end = 0;
  139. /* Restart counters on all processors -- blocking */
  140. pmc_start(NULL); 
  141. smp_call_function(pmc_start, (void *)NULL, 0, 1);
  142. return(0); 
  143. }
  144. void pmc_stop(void *data) 
  145. {
  146. /* Freeze all counters, leave everything else alone */
  147. mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
  148. }
  149. void pmc_start(void *data) 
  150. {
  151. /* Free all counters, leave everything else alone */
  152. mtspr( MMCR0, mfspr( MMCR0 ) & 0x7fffffff );
  153. }
  154. void pmc_touch_bolted(void *data) 
  155. {
  156. volatile int touch;
  157. /* Hack to fault the buffer into the segment table */
  158. touch = *((int *)(perfmon_base.profile_buffer));
  159. }
  160. void dump_pmc_struct(struct perfmon_struct *perfdata) 
  161. {
  162. unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
  163. if(cpu > MAX_PACAS) return;
  164. printk("PMC Control Mode: 0x%lxn", perfmon_base.state);
  165. printk("PMC[1 - 2] = 0x%16.16lx 0x%16.16lxn",
  166.        paca[cpu].pmcc[0], paca[cpu].pmcc[1]);
  167. printk("PMC[3 - 4] = 0x%16.16lx 0x%16.16lxn",
  168.        paca[cpu].pmcc[2], paca[cpu].pmcc[3]);
  169. printk("PMC[5 - 6] = 0x%16.16lx 0x%16.16lxn",
  170.        paca[cpu].pmcc[4], paca[cpu].pmcc[5]);
  171. printk("PMC[7 - 8] = 0x%16.16lx 0x%16.16lxn",
  172.        paca[cpu].pmcc[6], paca[cpu].pmcc[7]);
  173. perfdata->vdata.pmc_info.mode = perfmon_base.state;
  174. for(i = 0; i < 11; i++) 
  175. perfdata->vdata.pmc_info.pmc_base[i]  = paca[cpu].pmc[i];
  176. for(i = 0; i < 8; i++) 
  177. perfdata->vdata.pmc_info.pmc_cumulative[i]  = paca[cpu].pmcc[i];
  178. }
  179. void dump_hardware_pmc_struct(void *perfdata) 
  180. {
  181. unsigned int cpu = smp_processor_id();
  182. printk("PMC[%2.2d][1 - 4]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8xn",
  183.        cpu, (u32) mfspr(PMC1),(u32) mfspr(PMC2),(u32) mfspr(PMC3),(u32) mfspr(PMC4));
  184. printk("PMC[%2.2d][5 - 8]  = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8xn",
  185.        cpu, (u32) mfspr(PMC5),(u32) mfspr(PMC6),(u32) mfspr(PMC7),(u32) mfspr(PMC8));
  186. printk("MMCR[%2.2d][0,1,A] = 0x%8.8x 0x%8.8x 0x%8.8xn",
  187.        cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
  188. }
  189. int decr_profile(struct perfmon_struct *perfdata) 
  190. {
  191. int i;
  192. printk("Perfmon: NIA decrementer profilen");
  193. if(perfmon_base.state == PMC_STATE_INITIAL) {
  194. printk("Perfmon: failed - no buffer was allocated.n"); 
  195. return -1;
  196. }
  197. /* Stop counters on all processors -- blocking */
  198. pmc_stop(NULL); 
  199. smp_call_function(pmc_stop, (void *)NULL, 0, 1);
  200. for (i=0; i<MAX_PACAS; ++i) {
  201. paca[i].prof_mode = PMC_STATE_DECR_PROFILE;
  202. }
  203. perfmon_base.state = PMC_STATE_DECR_PROFILE; 
  204. mb(); 
  205. return 0;
  206. }
  207. int pmc_profile(struct perfmon_struct *perfdata) 
  208. {
  209. struct pmc_struct *pdata = &(perfdata->vdata.pmc);
  210. int i;
  211. printk("Perfmon: NIA PMC profile and CPIn");
  212. if(perfmon_base.state == PMC_STATE_INITIAL) {
  213. printk("Perfmon: failed - no buffer was allocated.n"); 
  214. return -1;
  215. }
  216. /* Stop counters on all processors -- blocking */
  217. pmc_stop(NULL); 
  218. smp_call_function(pmc_stop, (void *)NULL, 0, 1);
  219. for (i=0; i<MAX_PACAS; ++i) {
  220. paca[i].prof_mode = PMC_STATE_PROFILE_KERN;
  221. }
  222. perfmon_base.state = PMC_STATE_PROFILE_KERN; 
  223. pdata->pmc[0] = 0x7f000000;
  224. for(i = 1; i < 8; i++) 
  225. pdata->pmc[i] = 0x0;
  226. pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
  227. pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
  228. pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
  229. mb();
  230. pmc_configure((void *)perfdata);
  231. smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
  232. return 0;
  233. }
  234. int pmc_set_general(struct perfmon_struct *perfdata) 
  235. {
  236. int i;
  237. printk("Perfmon: PMC sampling - Generaln");
  238. if(perfmon_base.state == PMC_STATE_INITIAL) {
  239. printk("Perfmon: failed - no buffer was allocated.n"); 
  240. return -1;
  241. }
  242. /* Stop counters on all processors -- blocking */
  243. pmc_stop(NULL); 
  244. smp_call_function(pmc_stop, (void *)NULL, 0, 1);
  245. for (i=0; i<MAX_PACAS; ++i) {
  246. paca[i].prof_mode = PMC_STATE_TRACE_KERN;
  247. }
  248. perfmon_base.state = PMC_STATE_TRACE_KERN; 
  249. mb();
  250. pmc_configure((void *)perfdata);
  251. smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
  252. return 0;
  253. }
  254. int pmc_set_user_general(struct perfmon_struct *perfdata) 
  255. {
  256. struct pmc_struct *pdata = &(perfdata->vdata.pmc);
  257. int pid = perfdata->header.pid;
  258. struct task_struct *task;
  259. int i;
  260. printk("Perfmon: PMC sampling - general usern");
  261. if(perfmon_base.state == PMC_STATE_INITIAL) {
  262. printk("Perfmon: failed - no buffer was allocated.n"); 
  263. return -1;
  264. }
  265. if(pid) {
  266. printk("Perfmon: pid = 0x%xn", pid);
  267. read_lock(&tasklist_lock);
  268. task = find_task_by_pid(pid);
  269. if (task) {
  270. printk("Perfmon: task = 0x%lxn", (u64) task);
  271. task->thread.regs->msr |= 0x4;
  272. #if 0
  273. for(i = 0; i < 11; i++)
  274. task->thread.pmc[i] = pdata->pmc[i];
  275. #endif
  276. } else {
  277. printk("Perfmon: task not foundn");
  278. read_unlock(&tasklist_lock);
  279. return -1;
  280. }
  281. }
  282. read_unlock(&tasklist_lock);
  283. /* Stop counters on all processors -- blocking */
  284. pmc_stop(NULL); 
  285. smp_call_function(pmc_stop, (void *)NULL, 0, 1);
  286. for (i=0; i<MAX_PACAS; ++i) {
  287. paca[i].prof_mode = PMC_STATE_TRACE_USER;
  288. }
  289. perfmon_base.state = PMC_STATE_TRACE_USER; 
  290. mb();
  291. pmc_configure((void *)perfdata);
  292. smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
  293. return 0;
  294. }
  295. void pmc_configure(void *data)
  296. {
  297. struct paca_struct *lpaca = get_paca();
  298. struct perfmon_struct *perfdata = (struct perfmon_struct *)data;
  299. struct pmc_struct *pdata = &(perfdata->vdata.pmc);
  300. unsigned long cmd_rec, i;
  301. /* Indicate to hypervisor that we are using the PMCs */
  302. if(naca->platform == PLATFORM_ISERIES_LPAR)
  303. lpaca->xLpPacaPtr->xPMCRegsInUse = 1;
  304. /* Freeze all counters */
  305. mtspr( MMCR0, 0x80000000 ); mtspr( MMCR1, 0x00000000 );
  306. cmd_rec = 0xFFUL << 56;
  307. cmd_rec |= perfdata->header.type;
  308. *((unsigned long *)(perfmon_base.trace_buffer + perfmon_base.trace_end)) = cmd_rec;
  309. perfmon_base.trace_end += 8;
  310. /* Clear all the PMCs */
  311. mtspr( PMC1, 0 ); mtspr( PMC2, 0 ); mtspr( PMC3, 0 );
  312. mtspr( PMC4, 0 ); mtspr( PMC5, 0 ); mtspr( PMC6, 0 );
  313. mtspr( PMC7, 0 ); mtspr( PMC8, 0 );
  314. for(i = 0; i < 11; i++)
  315. lpaca->pmc[i]  = pdata->pmc[i];
  316. mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
  317. mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
  318. mtspr(PMC5, lpaca->pmc[4]); mtspr(PMC6, lpaca->pmc[5]);
  319. mtspr(PMC7, lpaca->pmc[6]); mtspr(PMC8, lpaca->pmc[7]);
  320. mtspr(MMCR1, lpaca->pmc[9]); mtspr(MMCRA, lpaca->pmc[10]);
  321. mb();
  322. /* Start all counters */
  323. mtspr( MMCR0, lpaca->pmc[8]);
  324. }