BIOS.WMPerfMonPluginInterrupts.Mod 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. MODULE WMPerfMonPluginInterrupts; (** AUTHOR "staubesv"; PURPOSE "Performance Monitor interrupt statistics plugin"; *)
  2. (**
  3. * This Performance Monitor plugin counts the number of interrupt occurences for the first 64 interrupt vectors.
  4. *
  5. * Usage:
  6. *
  7. * WMPerfMonPluginInterrupts.Install ~ loads this plugin Use System.Free WMPerfMonPluginInterrupts ~ to unload it
  8. *
  9. * Once loaded, the plugin is accessible using the Performance Monitor application -> WMPerfMon.Open ~
  10. *
  11. * Notes:
  12. *
  13. * - This plugin is not intended to run in productive environments
  14. * - When this plugin is loaded, first-level interrupt handlers for the first 64 interrupt vectors will be installed. As side effect, these
  15. * interrupts are enabled. Keep this in mind.
  16. * - IRQ8 (Real Time Clock) is programmed to deliver one interrupt per second (see Clock)
  17. *
  18. *
  19. * History:
  20. *
  21. * 30.03.2007 First release (staubesv)
  22. *)
  23. IMPORT
  24. WMPerfMonPlugins,
  25. Machine, Modules;
  26. CONST
  27. ModuleName = "WMPerfMonPluginInterrupts";
  28. TYPE
  29. InterruptStatistics = OBJECT(WMPerfMonPlugins.Plugin)
  30. PROCEDURE Init(p : WMPerfMonPlugins.Parameter);
  31. VAR ds : WMPerfMonPlugins.DatasetDescriptor;
  32. BEGIN
  33. p.name := "Interrupts"; p.description := "Interrupt statistics";
  34. p.modulename := ModuleName;
  35. p.autoMin := FALSE; p.autoMax := TRUE; p.minDigits := 7;
  36. NEW(ds, 44);
  37. (* pre-defined interrupts *)
  38. ds[0].name := "INT0-Divide Error";
  39. ds[1].name := "INT1-Reserved";
  40. ds[2].name := "INT2-NMI";
  41. ds[3].name := "INT3-Breakpoint";
  42. ds[4].name := "INT4-Overflow";
  43. ds[5].name := "INT5-BOUND range exceeded";
  44. ds[6].name := "INT6-Invalid Opcode";
  45. ds[7].name := "INT7-No Math Coprocessor";
  46. ds[8].name := "INT8-Double Fault";
  47. ds[9].name := "INT9-CoprocessorSegment Overrun";
  48. ds[10].name := "INT10-Invalid TSS";
  49. ds[11].name := "INT11-Segment not present";
  50. ds[12].name := "INT12-Stack segment fault";
  51. ds[13].name := "INT13-General Protection";
  52. ds[14].name := "INT14-Page Fault";
  53. ds[15].name := "INT15-Reserved";
  54. ds[16].name := "INT16-Math Fault";
  55. ds[17].name := "INT17-Alignment Check";
  56. ds[18].name := "INT18-Machine Check";
  57. ds[19].name := "INT19-SIMD FP Exception";
  58. ds[20].name := "INT32-IRQ0 (Timer)";
  59. ds[21].name := "INT33-IRQ1 (Keyboard)";
  60. (* IRQ 2 not monitored since used for cascading PICs *)
  61. ds[22].name := "INT35-IRQ3";
  62. ds[23].name := "INT36-IRQ4";
  63. ds[24].name := "INT37-IRQ5";
  64. ds[25].name := "INT38-IRQ6";
  65. ds[26].name := "INT39-IRQ7";
  66. ds[27].name := "INT40-IRQ8 (RTC)";
  67. ds[28].name := "INT41-IRQ9";
  68. ds[29].name := "INT42-IRQ10";
  69. ds[30].name := "INT43-IRQ11";
  70. ds[31].name := "INT44-IRQ12";
  71. ds[32].name := "INT45-IRQ13";
  72. ds[33].name := "INT46-IRQ14";
  73. ds[34].name := "INT47-IRQ15";
  74. ds[35].name := "INT49-SMP Kernel Call";
  75. ds[36].name := "INT58-SoftInt";
  76. ds[37].name := "INT59-SMP Local IPC";
  77. ds[38].name := "INT60-SMP Timer Interrupt";
  78. ds[39].name := "INT61-SMP IPC ";
  79. ds[40].name := "INT62-SMP Error Interrupt";
  80. ds[41].name := "INT63-SMP Spurious Interrupt";
  81. ds[42].name := "Total"; INCL(ds[42].flags, WMPerfMonPlugins.Sum);
  82. ds[43].name := "Others";
  83. p.datasetDescriptor := ds;
  84. END Init;
  85. PROCEDURE UpdateDataset;
  86. VAR i, offset, temp : LONGINT;
  87. BEGIN
  88. FOR i := 0 TO 19 DO (* pre-defined interrupts *)
  89. dataset[i] := interrupts[i].count;
  90. END;
  91. offset := Machine.IRQ0;
  92. dataset[20] := interrupts[offset + 0].count;
  93. dataset[21] := interrupts[offset + 1].count;
  94. (* Skip IRQ 2 *)
  95. FOR i := 3 TO 15 DO
  96. dataset[22 - 3 + i] := interrupts[offset + i].count;
  97. END;
  98. dataset[35] := interrupts[49].count;
  99. dataset[36] := interrupts[58].count;
  100. dataset[37] := interrupts[59].count;
  101. dataset[38] := interrupts[60].count;
  102. dataset[39] := interrupts[61].count;
  103. dataset[40] := interrupts[62].count;
  104. dataset[41] := interrupts[63].count;
  105. temp := others;
  106. dataset[42] := temp;
  107. FOR i := 0 TO 41 DO
  108. dataset[42] := dataset[42] + dataset[i];
  109. END;
  110. dataset[43] := temp;
  111. END UpdateDataset;
  112. END InterruptStatistics;
  113. InterruptInfo = RECORD
  114. count : LONGINT;
  115. handlerInstalled : BOOLEAN;
  116. isOther : BOOLEAN;
  117. END;
  118. VAR
  119. interrupts : ARRAY 256 OF InterruptInfo;
  120. others : LONGINT;
  121. PROCEDURE HandleInterrupts(VAR state : Machine.State);
  122. BEGIN
  123. IF (0 <= state.INT) & (state.INT < 256) THEN
  124. IF interrupts[state.INT].handlerInstalled THEN
  125. Machine.AtomicInc(interrupts[state.INT].count);
  126. ELSE
  127. Machine.AtomicInc(others);
  128. END;
  129. END;
  130. END HandleInterrupts;
  131. PROCEDURE RegisterHandlers;
  132. VAR i : LONGINT;
  133. BEGIN
  134. FOR i := 0 TO LEN(interrupts)-1 DO interrupts[i].isOther := TRUE; END;
  135. FOR i := 0 TO 19 DO interrupts[i].isOther := FALSE; END;
  136. FOR i := 32 TO 47 DO interrupts[i].isOther := FALSE; END;
  137. interrupts[49].isOther := FALSE;
  138. FOR i := 58 TO 63 DO interrupts[i].isOther := FALSE; END;
  139. FOR i := 244 TO 253 DO interrupts[i].isOther := FALSE; END;
  140. FOR i := 0 TO 63 DO
  141. IF (i # 34) & (i # 39) THEN (* IRQ2 used for cascading *)
  142. Machine.InstallHandler(HandleInterrupts, i);
  143. interrupts[i].handlerInstalled := TRUE;
  144. END;
  145. END;
  146. END RegisterHandlers;
  147. PROCEDURE UnregisterHandlers;
  148. VAR i : LONGINT;
  149. BEGIN
  150. FOR i := 0 TO LEN(interrupts)-1 DO
  151. IF interrupts[i].handlerInstalled THEN
  152. Machine.RemoveHandler(HandleInterrupts, i);
  153. interrupts[i].count := 0;
  154. interrupts[i].handlerInstalled := FALSE;
  155. END;
  156. END;
  157. END UnregisterHandlers;
  158. PROCEDURE InitPlugin;
  159. VAR par : WMPerfMonPlugins.Parameter; plugin : InterruptStatistics;
  160. BEGIN
  161. NEW(par); NEW(plugin, par);
  162. END InitPlugin;
  163. PROCEDURE Install*;
  164. END Install;
  165. PROCEDURE Cleanup;
  166. BEGIN
  167. UnregisterHandlers;
  168. WMPerfMonPlugins.updater.RemoveByModuleName(ModuleName);
  169. END Cleanup;
  170. BEGIN
  171. Modules.InstallTermHandler(Cleanup);
  172. RegisterHandlers;
  173. InitPlugin;
  174. END WMPerfMonPluginInterrupts.
  175. WMPerfMonPluginInterrupts.Install ~ System.Free WMPerfMonPluginInterrupts ~