insnmeas.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # -*- coding: utf-8 -*-
  2. #
  3. # AWL simulator - Instruction timing measurement
  4. #
  5. # Copyright 2019 Michael Buesch <m@bues.ch>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. from __future__ import division, absolute_import, print_function, unicode_literals
  22. #from awlsim.common.cython_support cimport * #@cy
  23. from awlsim.common.compat import *
  24. from awlsim.common.util import *
  25. from awlsim.common.exceptions import *
  26. from awlsim.common.monotonic import * #+cimport
  27. #from awlsim.core.insnmeas cimport * #@cy
  28. from awlsim.core.instructions.main import * #+cimport
  29. from awlsim.core.instructions.types import * #+cimport
  30. import time
  31. __all__ = [
  32. "InsnMeas",
  33. ]
  34. class InsnMeasData(object): #+cdef
  35. def __init__(self):
  36. self.measured = False
  37. self.measStart = 0.0
  38. self.cumRt = 0.0
  39. self.count = 0
  40. self.minRt = 9999.0
  41. self.maxRt = 0.0
  42. @property
  43. def avgRt(self):
  44. if self.count == 0:
  45. return 9999.0
  46. return self.cumRt / float(self.count)
  47. def subtractCal(self, calOffset):
  48. new = InsnMeasData()
  49. new.minRt = max(1.0e-9, self.minRt - calOffset)
  50. new.maxRt = max(1.0e-9, self.maxRt - calOffset)
  51. new.cumRt = max(1.0e-9, self.avgRt - calOffset)
  52. new.count = 1
  53. return new
  54. def dump(self, name):
  55. name += " " * (6 - len(name))
  56. return "%s: min: %.3f us, max: %.3f us, avg: %.3f us" % (
  57. name,
  58. self.minRt * 1.0e6,
  59. self.maxRt * 1.0e6,
  60. self.avgRt * 1.0e6)
  61. class InsnMeas(object): #+cdef
  62. def __init__(self):
  63. self.__perf_counter = time.perf_counter
  64. self.__data = [None] * (AwlInsnTypes.NR_TYPES + 1)
  65. for i in range(AwlInsnTypes.NR_TYPES + 1):
  66. self.__data[i] = InsnMeasData()
  67. printInfo("Running instruction measurement offset calibration...")
  68. for i in range(2000000):
  69. self.meas(True, AwlInsnTypes.NR_TYPES)
  70. self.meas(False, AwlInsnTypes.NR_TYPES)
  71. measData = self.__data[AwlInsnTypes.NR_TYPES]
  72. printInfo("Instruction measurement cal offset = %f us" % (
  73. measData.avgRt * 1000000.0))
  74. def meas(self, begin, insnType): #@nocy
  75. #@cy cdef void meas(self, _Bool begin, uint32_t insnType):
  76. #@cy cdef InsnMeasData measData
  77. #@cy cdef double rt
  78. #@cy cdef double now
  79. now = self.__perf_counter()
  80. measData = self.__data[insnType]
  81. if begin:
  82. measData.measStart = now
  83. else:
  84. rt = now - measData.measStart
  85. measData.cumRt += rt
  86. measData.count += 1
  87. measData.minRt = min(measData.minRt, rt)
  88. measData.maxRt = max(measData.maxRt, rt)
  89. measData.measured = True
  90. @property
  91. def haveAnyMeasurements(self):
  92. return any(self.__data[i].measured
  93. for i in range(AwlInsnTypes.NR_TYPES))
  94. @property
  95. def __calOffset(self):
  96. cal = self.__data[AwlInsnTypes.NR_TYPES]
  97. calOffset = cal.avgRt
  98. return calOffset
  99. @property
  100. def __allMeasData(self):
  101. calOffset = self.__calOffset
  102. for insnType in range(AwlInsnTypes.NR_TYPES):
  103. measData = self.__data[insnType]
  104. if measData.measured:
  105. measData = measData.subtractCal(calOffset)
  106. yield insnType, measData
  107. def dump(self):
  108. if not self.haveAnyMeasurements:
  109. return
  110. printInfo("")
  111. printInfo("Instruction time measurements:")
  112. for insnType, measData in self.__allMeasData:
  113. name = AwlInsnTypes.type2name_german[insnType]
  114. printInfo(measData.dump(name))
  115. def dumpCSV(self):
  116. if not self.haveAnyMeasurements:
  117. return ""
  118. ret = [ "instruction type;"
  119. "instruction name;"
  120. "minimum runtime (µs);"
  121. "maximum runtime (µs);"
  122. "average runtime (µs)" ]
  123. for insnType, measData in self.__allMeasData:
  124. name = AwlInsnTypes.type2name_german[insnType]
  125. ret.append("%d; %s;%.3f;%.3f;%.3f" % (
  126. insnType,
  127. AwlInsnTypes.type2name_german[insnType],
  128. measData.minRt * 1.0e6,
  129. measData.maxRt * 1.0e6,
  130. measData.avgRt * 1.0e6))
  131. return "\n".join(ret)