py_stats.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include "hooks_py.h"
  2. #include "simulator.h"
  3. #include "clock_skew_minimization_object.h"
  4. #include "stats.h"
  5. #include "magic_server.h"
  6. #include "thread_stats_manager.h"
  7. //////////
  8. // get(): retrieve a stats value
  9. //////////
  10. static PyObject *
  11. getStatsValue(PyObject *self, PyObject *args)
  12. {
  13. const char *objectName = NULL, *metricName = NULL;
  14. long int index = -1;
  15. if (!PyArg_ParseTuple(args, "sls", &objectName, &index, &metricName))
  16. return NULL;
  17. StatsMetricBase *metric = Sim()->getStatsManager()->getMetricObject(objectName, index, metricName);
  18. if (!metric) {
  19. PyErr_SetString(PyExc_ValueError, "Stats metric not found");
  20. return NULL;
  21. }
  22. return PyLong_FromUnsignedLongLong(metric->recordMetric());
  23. }
  24. //////////
  25. // getter(): return a statsGetterObject Python object which, when called, returns a stats value
  26. //////////
  27. typedef struct {
  28. PyObject_HEAD
  29. StatsMetricBase *metric;
  30. } statsGetterObject;
  31. static PyObject *
  32. statsGetterGet(PyObject *self, PyObject *args, PyObject *kw)
  33. {
  34. statsGetterObject *getter = (statsGetterObject *)self;
  35. StatsMetricBase *metric = getter->metric;
  36. return PyLong_FromUnsignedLongLong(metric->recordMetric());
  37. }
  38. static PyTypeObject statsGetterType = {
  39. PyObject_HEAD_INIT(NULL)
  40. 0, /*ob_size*/
  41. "statsGetter", /*tp_name*/
  42. sizeof(statsGetterObject), /*tp_basicsize*/
  43. 0, /*tp_itemsize*/
  44. 0, /*tp_dealloc*/
  45. 0, /*tp_print*/
  46. 0, /*tp_getattr*/
  47. 0, /*tp_setattr*/
  48. 0, /*tp_compare*/
  49. 0, /*tp_repr*/
  50. 0, /*tp_as_number*/
  51. 0, /*tp_as_sequence*/
  52. 0, /*tp_as_mapping*/
  53. 0, /*tp_hash */
  54. statsGetterGet, /*tp_call*/
  55. 0, /*tp_str*/
  56. 0, /*tp_getattro*/
  57. 0, /*tp_setattro*/
  58. 0, /*tp_as_buffer*/
  59. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  60. "Stats getter objects", /*tp_doc*/
  61. 0, /*tp_traverse*/
  62. 0, /*tp_clear*/
  63. 0, /*tp_richcompare*/
  64. 0, /*tp_weaklistoffset*/
  65. 0, /*tp_iter*/
  66. 0, /*tp_iternext*/
  67. 0, /*tp_methods*/
  68. 0, /*tp_members*/
  69. 0, /*tp_getset*/
  70. 0, /*tp_base*/
  71. 0, /*tp_dict*/
  72. 0, /*tp_descr_get*/
  73. 0, /*tp_descr_set*/
  74. 0, /*tp_dictoffset*/
  75. 0, /*tp_init*/
  76. 0, /*tp_alloc*/
  77. 0, /*tp_new*/
  78. 0, /*tp_free*/
  79. 0, /*tp_is_gc*/
  80. 0, /*tp_bases*/
  81. 0, /*tp_mro*/
  82. 0, /*tp_cache*/
  83. 0, /*tp_subclasses*/
  84. 0, /*tp_weaklist*/
  85. 0, /*tp_del*/
  86. 0, /*tp_version_tag*/
  87. };
  88. static PyObject *
  89. getStatsGetter(PyObject *self, PyObject *args)
  90. {
  91. const char *objectName = NULL, *metricName = NULL;
  92. long int index = -1;
  93. if (!PyArg_ParseTuple(args, "sls", &objectName, &index, &metricName))
  94. return NULL;
  95. StatsMetricBase *metric = Sim()->getStatsManager()->getMetricObject(objectName, index, metricName);
  96. if (!metric) {
  97. PyErr_SetString(PyExc_ValueError, "Stats metric not found");
  98. return NULL;
  99. }
  100. statsGetterObject *pGetter = PyObject_New(statsGetterObject, &statsGetterType);
  101. pGetter->metric = metric;
  102. return (PyObject *)pGetter;
  103. }
  104. //////////
  105. // write(): write the current set of statistics out to sim.stats or our own file
  106. //////////
  107. static PyObject *
  108. writeStats(PyObject *self, PyObject *args)
  109. {
  110. const char *prefix = NULL;
  111. if (!PyArg_ParseTuple(args, "s", &prefix))
  112. return NULL;
  113. Sim()->getStatsManager()->recordStats(prefix);
  114. Py_RETURN_NONE;
  115. }
  116. //////////
  117. // register(): register a callback function that returns a statistics value
  118. //////////
  119. static UInt64 statsCallback(String objectName, UInt32 index, String metricName, UInt64 _pFunc)
  120. {
  121. PyObject *pFunc = (PyObject*)_pFunc;
  122. PyObject *pResult = HooksPy::callPythonFunction(pFunc, Py_BuildValue("(sls)", objectName.c_str(), index, metricName.c_str()));
  123. if (!pResult || !PyLong_Check(pResult)) {
  124. LOG_PRINT_WARNING("Stats callback: return value must be (convertable into) 64-bit unsigned integer");
  125. if (pResult)
  126. Py_XDECREF(pResult);
  127. return 0;
  128. }
  129. UInt64 val = PyLong_AsLongLong(pResult);
  130. Py_XDECREF(pResult);
  131. return val;
  132. }
  133. static PyObject *
  134. registerStats(PyObject *self, PyObject *args)
  135. {
  136. const char *objectName = NULL, *metricName = NULL;
  137. long int index = -1;
  138. PyObject *pFunc = NULL;
  139. if (!PyArg_ParseTuple(args, "slsO", &objectName, &index, &metricName, &pFunc))
  140. return NULL;
  141. if (!PyCallable_Check(pFunc)) {
  142. PyErr_SetString(PyExc_TypeError, "Fourth argument must be callable");
  143. return NULL;
  144. }
  145. Py_INCREF(pFunc);
  146. Sim()->getStatsManager()->registerMetric(new StatsMetricCallback(objectName, index, metricName, (StatsCallback)statsCallback, (UInt64)pFunc));
  147. Py_RETURN_NONE;
  148. }
  149. static PyObject *
  150. registerPerThread(PyObject *self, PyObject *args)
  151. {
  152. const char *objectName = NULL, *metricName = NULL, *sPerThread = NULL;
  153. if (!PyArg_ParseTuple(args, "sss", &sPerThread, &objectName, &metricName))
  154. return NULL;
  155. ThreadStatNamedStat::registerStat(strdup(sPerThread), objectName, metricName);
  156. Py_RETURN_NONE;
  157. }
  158. //////////
  159. // marker(): record a marker
  160. //////////
  161. static PyObject *
  162. writeMarker(PyObject *self, PyObject *args)
  163. {
  164. UInt64 core_id = INVALID_CORE_ID, thread_id = INVALID_THREAD_ID, arg0 = 0, arg1 = 0;
  165. const char *description = NULL;
  166. if (!PyArg_ParseTuple(args, "llll|z", &core_id, &thread_id, &arg0, &arg1, &description))
  167. return NULL;
  168. Sim()->getStatsManager()->logMarker(Sim()->getClockSkewMinimizationServer()->getGlobalTime(), core_id, thread_id, arg0, arg1, description);
  169. Py_RETURN_NONE;
  170. }
  171. //////////
  172. // time(): Return current global time in femtoseconds
  173. //////////
  174. static PyObject *
  175. getTime(PyObject *self, PyObject *args)
  176. {
  177. SubsecondTime time = Sim()->getClockSkewMinimizationServer()->getGlobalTime();
  178. return PyLong_FromUnsignedLongLong(time.getFS());
  179. }
  180. //////////
  181. // icount(): Return current global instruction count
  182. //////////
  183. static PyObject *
  184. getIcount(PyObject *self, PyObject *args)
  185. {
  186. UInt64 icount = MagicServer::getGlobalInstructionCount();
  187. return PyLong_FromUnsignedLongLong(icount);
  188. }
  189. //////////
  190. // module definition
  191. //////////
  192. static PyMethodDef PyStatsMethods[] = {
  193. {"get", getStatsValue, METH_VARARGS, "Retrieve current value of statistic (objectName, index, metricName)."},
  194. {"getter", getStatsGetter, METH_VARARGS, "Return object to retrieve statistics value."},
  195. {"write", writeStats, METH_VARARGS, "Write statistics (<prefix>, [<filename>])."},
  196. {"register", registerStats, METH_VARARGS, "Register callback that defines statistics value for (objectName, index, metricName)."},
  197. {"register_per_thread", registerPerThread, METH_VARARGS, "Add a per-thread statistic (perthreadName) based on a named statistic (objectName, metricName)."},
  198. {"marker", writeMarker, METH_VARARGS, "Record a marker (coreid, threadid, arg0, arg1, [description])."},
  199. {"time", getTime, METH_VARARGS, "Retrieve the current global time in femtoseconds (approximate, last barrier)."},
  200. {"icount", getIcount, METH_VARARGS, "Retrieve current global instruction count."},
  201. {NULL, NULL, 0, NULL} /* Sentinel */
  202. };
  203. void HooksPy::PyStats::setup(void)
  204. {
  205. PyObject *pModule = Py_InitModule("sim_stats", PyStatsMethods);
  206. statsGetterType.tp_new = PyType_GenericNew;
  207. if (PyType_Ready(&statsGetterType) < 0)
  208. return;
  209. Py_INCREF(&statsGetterType);
  210. PyModule_AddObject(pModule, "Getter", (PyObject *)&statsGetterType);
  211. }