/Modules/_hotshot.c

http://unladen-swallow.googlecode.com/ · C · 1643 lines · 1319 code · 162 blank · 162 comment · 249 complexity · 5979008e45d40680a3b40d501ea01b87 MD5 · raw file

  1. /*
  2. * This is the High Performance Python Profiler portion of HotShot.
  3. */
  4. #include "Python.h"
  5. #include "code.h"
  6. #include "eval.h"
  7. #include "frameobject.h"
  8. #include "structmember.h"
  9. /*
  10. * Which timer to use should be made more configurable, but that should not
  11. * be difficult. This will do for now.
  12. */
  13. #ifdef MS_WINDOWS
  14. #include <windows.h>
  15. #ifdef HAVE_DIRECT_H
  16. #include <direct.h> /* for getcwd() */
  17. #endif
  18. typedef __int64 hs_time;
  19. #define GETTIMEOFDAY(P_HS_TIME) \
  20. { LARGE_INTEGER _temp; \
  21. QueryPerformanceCounter(&_temp); \
  22. *(P_HS_TIME) = _temp.QuadPart; }
  23. #else
  24. #ifndef HAVE_GETTIMEOFDAY
  25. #error "This module requires gettimeofday() on non-Windows platforms!"
  26. #endif
  27. #if (defined(PYOS_OS2) && defined(PYCC_GCC)) || defined(__QNX__)
  28. #include <sys/time.h>
  29. #else
  30. #include <sys/resource.h>
  31. #include <sys/times.h>
  32. #endif
  33. typedef struct timeval hs_time;
  34. #endif
  35. #if !defined(__cplusplus) && !defined(inline)
  36. #ifdef __GNUC__
  37. #define inline __inline
  38. #endif
  39. #endif
  40. #ifndef inline
  41. #define inline
  42. #endif
  43. #define BUFFERSIZE 10240
  44. #if defined(PYOS_OS2) && defined(PYCC_GCC)
  45. #define PATH_MAX 260
  46. #endif
  47. #if defined(__sgi) && _COMPILER_VERSION>700 && !defined(PATH_MAX)
  48. /* fix PATH_MAX not being defined with MIPSPro 7.x
  49. if mode is ANSI C (default) */
  50. #define PATH_MAX 1024
  51. #endif
  52. #ifndef PATH_MAX
  53. # ifdef MAX_PATH
  54. # define PATH_MAX MAX_PATH
  55. # elif defined (_POSIX_PATH_MAX)
  56. # define PATH_MAX _POSIX_PATH_MAX
  57. # else
  58. # error "Need a defn. for PATH_MAX in _hotshot.c"
  59. # endif
  60. #endif
  61. typedef struct {
  62. PyObject_HEAD
  63. PyObject *filemap;
  64. PyObject *logfilename;
  65. Py_ssize_t index;
  66. unsigned char buffer[BUFFERSIZE];
  67. FILE *logfp;
  68. int lineevents;
  69. int linetimings;
  70. int frametimings;
  71. /* size_t filled; */
  72. int active;
  73. int next_fileno;
  74. hs_time prev_timeofday;
  75. } ProfilerObject;
  76. typedef struct {
  77. PyObject_HEAD
  78. PyObject *info;
  79. FILE *logfp;
  80. int linetimings;
  81. int frametimings;
  82. } LogReaderObject;
  83. static PyObject * ProfilerError = NULL;
  84. #ifndef MS_WINDOWS
  85. #ifdef GETTIMEOFDAY_NO_TZ
  86. #define GETTIMEOFDAY(ptv) gettimeofday((ptv))
  87. #else
  88. #define GETTIMEOFDAY(ptv) gettimeofday((ptv), (struct timezone *)NULL)
  89. #endif
  90. #endif
  91. /* The log reader... */
  92. PyDoc_STRVAR(logreader_close__doc__,
  93. "close()\n"
  94. "Close the log file, preventing additional records from being read.");
  95. static PyObject *
  96. logreader_close(LogReaderObject *self, PyObject *args)
  97. {
  98. if (self->logfp != NULL) {
  99. fclose(self->logfp);
  100. self->logfp = NULL;
  101. }
  102. Py_INCREF(Py_None);
  103. return Py_None;
  104. }
  105. PyDoc_STRVAR(logreader_fileno__doc__,
  106. "fileno() -> file descriptor\n"
  107. "Returns the file descriptor for the log file, if open.\n"
  108. "Raises ValueError if the log file is closed.");
  109. static PyObject *
  110. logreader_fileno(LogReaderObject *self)
  111. {
  112. if (self->logfp == NULL) {
  113. PyErr_SetString(PyExc_ValueError,
  114. "logreader's file object already closed");
  115. return NULL;
  116. }
  117. return PyInt_FromLong(fileno(self->logfp));
  118. }
  119. /* Log File Format
  120. * ---------------
  121. *
  122. * The log file consists of a sequence of variable-length records.
  123. * Each record is identified with a record type identifier in two
  124. * bits of the first byte. The two bits are the "least significant"
  125. * bits of the byte.
  126. *
  127. * Low bits: Opcode: Meaning:
  128. * 0x00 ENTER enter a frame
  129. * 0x01 EXIT exit a frame
  130. * 0x02 LINENO execution moved onto a different line
  131. * 0x03 OTHER more bits are needed to deecode
  132. *
  133. * If the type is OTHER, the record is not packed so tightly, and the
  134. * remaining bits are used to disambiguate the record type. These
  135. * records are not used as frequently so compaction is not an issue.
  136. * Each of the first three record types has a highly tailored
  137. * structure that allows it to be packed tightly.
  138. *
  139. * The OTHER records have the following identifiers:
  140. *
  141. * First byte: Opcode: Meaning:
  142. * 0x13 ADD_INFO define a key/value pair
  143. * 0x23 DEFINE_FILE define an int->filename mapping
  144. * 0x33 LINE_TIMES indicates if LINENO events have tdeltas
  145. * 0x43 DEFINE_FUNC define a (fileno,lineno)->funcname mapping
  146. * 0x53 FRAME_TIMES indicates if ENTER/EXIT events have tdeltas
  147. *
  148. * Packed Integers
  149. *
  150. * "Packed integers" are non-negative integer values encoded as a
  151. * sequence of bytes. Each byte is encoded such that the most
  152. * significant bit is set if the next byte is also part of the
  153. * integer. Each byte provides bits to the least-significant end of
  154. * the result; the accumulated value must be shifted up to place the
  155. * new bits into the result.
  156. *
  157. * "Modified packed integers" are packed integers where only a portion
  158. * of the first byte is used. In the rest of the specification, these
  159. * are referred to as "MPI(n,name)", where "n" is the number of bits
  160. * discarded from the least-signicant positions of the byte, and
  161. * "name" is a name being given to those "discarded" bits, since they
  162. * are a field themselves.
  163. *
  164. * ENTER records:
  165. *
  166. * MPI(2,type) fileno -- type is 0x00
  167. * PI lineno
  168. * PI tdelta -- iff frame times are enabled
  169. *
  170. * EXIT records
  171. *
  172. * MPI(2,type) tdelta -- type is 0x01; tdelta will be 0
  173. * if frame times are disabled
  174. *
  175. * LINENO records
  176. *
  177. * MPI(2,type) lineno -- type is 0x02
  178. * PI tdelta -- iff LINENO includes it
  179. *
  180. * ADD_INFO records
  181. *
  182. * BYTE type -- always 0x13
  183. * PI len1 -- length of first string
  184. * BYTE string1[len1] -- len1 bytes of string data
  185. * PI len2 -- length of second string
  186. * BYTE string2[len2] -- len2 bytes of string data
  187. *
  188. * DEFINE_FILE records
  189. *
  190. * BYTE type -- always 0x23
  191. * PI fileno
  192. * PI len -- length of filename
  193. * BYTE filename[len] -- len bytes of string data
  194. *
  195. * DEFINE_FUNC records
  196. *
  197. * BYTE type -- always 0x43
  198. * PI fileno
  199. * PI lineno
  200. * PI len -- length of funcname
  201. * BYTE funcname[len] -- len bytes of string data
  202. *
  203. * LINE_TIMES records
  204. *
  205. * This record can be used only before the start of ENTER/EXIT/LINENO
  206. * records. If have_tdelta is true, LINENO records will include the
  207. * tdelta field, otherwise it will be omitted. If this record is not
  208. * given, LINENO records will not contain the tdelta field.
  209. *
  210. * BYTE type -- always 0x33
  211. * BYTE have_tdelta -- 0 if LINENO does *not* have
  212. * timing information
  213. * FRAME_TIMES records
  214. *
  215. * This record can be used only before the start of ENTER/EXIT/LINENO
  216. * records. If have_tdelta is true, ENTER and EXIT records will
  217. * include the tdelta field, otherwise it will be omitted. If this
  218. * record is not given, ENTER and EXIT records will contain the tdelta
  219. * field.
  220. *
  221. * BYTE type -- always 0x53
  222. * BYTE have_tdelta -- 0 if ENTER/EXIT do *not* have
  223. * timing information
  224. */
  225. #define WHAT_ENTER 0x00
  226. #define WHAT_EXIT 0x01
  227. #define WHAT_LINENO 0x02
  228. #define WHAT_OTHER 0x03 /* only used in decoding */
  229. #define WHAT_ADD_INFO 0x13
  230. #define WHAT_DEFINE_FILE 0x23
  231. #define WHAT_LINE_TIMES 0x33
  232. #define WHAT_DEFINE_FUNC 0x43
  233. #define WHAT_FRAME_TIMES 0x53
  234. #define ERR_NONE 0
  235. #define ERR_EOF -1
  236. #define ERR_EXCEPTION -2
  237. #define ERR_BAD_RECTYPE -3
  238. #define PISIZE (sizeof(int) + 1)
  239. #define MPISIZE (PISIZE + 1)
  240. /* Maximum size of "normal" events -- nothing that contains string data */
  241. #define MAXEVENTSIZE (MPISIZE + PISIZE*2)
  242. /* Unpack a packed integer; if "discard" is non-zero, unpack a modified
  243. * packed integer with "discard" discarded bits.
  244. */
  245. static int
  246. unpack_packed_int(LogReaderObject *self, int *pvalue, int discard)
  247. {
  248. int c;
  249. int accum = 0;
  250. int bits = 0;
  251. int cont;
  252. do {
  253. /* read byte */
  254. if ((c = fgetc(self->logfp)) == EOF)
  255. return ERR_EOF;
  256. accum |= ((c & 0x7F) >> discard) << bits;
  257. bits += (7 - discard);
  258. cont = c & 0x80;
  259. discard = 0;
  260. } while (cont);
  261. *pvalue = accum;
  262. return 0;
  263. }
  264. /* Unpack a string, which is encoded as a packed integer giving the
  265. * length of the string, followed by the string data.
  266. */
  267. static int
  268. unpack_string(LogReaderObject *self, PyObject **pvalue)
  269. {
  270. int i;
  271. int len;
  272. int err;
  273. int ch;
  274. char *buf;
  275. if ((err = unpack_packed_int(self, &len, 0)))
  276. return err;
  277. buf = (char *)malloc(len);
  278. if (!buf) {
  279. PyErr_NoMemory();
  280. return ERR_EXCEPTION;
  281. }
  282. for (i=0; i < len; i++) {
  283. ch = fgetc(self->logfp);
  284. buf[i] = ch;
  285. if (ch == EOF) {
  286. free(buf);
  287. return ERR_EOF;
  288. }
  289. }
  290. *pvalue = PyString_FromStringAndSize(buf, len);
  291. free(buf);
  292. if (*pvalue == NULL) {
  293. return ERR_EXCEPTION;
  294. }
  295. return 0;
  296. }
  297. static int
  298. unpack_add_info(LogReaderObject *self)
  299. {
  300. PyObject *key;
  301. PyObject *value = NULL;
  302. int err;
  303. err = unpack_string(self, &key);
  304. if (!err) {
  305. err = unpack_string(self, &value);
  306. if (err)
  307. Py_DECREF(key);
  308. else {
  309. PyObject *list = PyDict_GetItem(self->info, key);
  310. if (list == NULL) {
  311. list = PyList_New(0);
  312. if (list == NULL) {
  313. err = ERR_EXCEPTION;
  314. goto finally;
  315. }
  316. if (PyDict_SetItem(self->info, key, list)) {
  317. Py_DECREF(list);
  318. err = ERR_EXCEPTION;
  319. goto finally;
  320. }
  321. Py_DECREF(list);
  322. }
  323. if (PyList_Append(list, value))
  324. err = ERR_EXCEPTION;
  325. }
  326. }
  327. finally:
  328. Py_XDECREF(key);
  329. Py_XDECREF(value);
  330. return err;
  331. }
  332. static void
  333. eof_error(LogReaderObject *self)
  334. {
  335. fclose(self->logfp);
  336. self->logfp = NULL;
  337. PyErr_SetString(PyExc_EOFError,
  338. "end of file with incomplete profile record");
  339. }
  340. static PyObject *
  341. logreader_tp_iternext(LogReaderObject *self)
  342. {
  343. int c;
  344. int what;
  345. int err = ERR_NONE;
  346. int lineno = -1;
  347. int fileno = -1;
  348. int tdelta = -1;
  349. PyObject *s1 = NULL, *s2 = NULL;
  350. PyObject *result = NULL;
  351. #if 0
  352. unsigned char b0, b1;
  353. #endif
  354. if (self->logfp == NULL) {
  355. PyErr_SetString(ProfilerError,
  356. "cannot iterate over closed LogReader object");
  357. return NULL;
  358. }
  359. restart:
  360. /* decode the record type */
  361. if ((c = fgetc(self->logfp)) == EOF) {
  362. fclose(self->logfp);
  363. self->logfp = NULL;
  364. return NULL;
  365. }
  366. what = c & WHAT_OTHER;
  367. if (what == WHAT_OTHER)
  368. what = c; /* need all the bits for type */
  369. else
  370. ungetc(c, self->logfp); /* type byte includes packed int */
  371. switch (what) {
  372. case WHAT_ENTER:
  373. err = unpack_packed_int(self, &fileno, 2);
  374. if (!err) {
  375. err = unpack_packed_int(self, &lineno, 0);
  376. if (self->frametimings && !err)
  377. err = unpack_packed_int(self, &tdelta, 0);
  378. }
  379. break;
  380. case WHAT_EXIT:
  381. err = unpack_packed_int(self, &tdelta, 2);
  382. break;
  383. case WHAT_LINENO:
  384. err = unpack_packed_int(self, &lineno, 2);
  385. if (self->linetimings && !err)
  386. err = unpack_packed_int(self, &tdelta, 0);
  387. break;
  388. case WHAT_ADD_INFO:
  389. err = unpack_add_info(self);
  390. break;
  391. case WHAT_DEFINE_FILE:
  392. err = unpack_packed_int(self, &fileno, 0);
  393. if (!err) {
  394. err = unpack_string(self, &s1);
  395. if (!err) {
  396. Py_INCREF(Py_None);
  397. s2 = Py_None;
  398. }
  399. }
  400. break;
  401. case WHAT_DEFINE_FUNC:
  402. err = unpack_packed_int(self, &fileno, 0);
  403. if (!err) {
  404. err = unpack_packed_int(self, &lineno, 0);
  405. if (!err)
  406. err = unpack_string(self, &s1);
  407. }
  408. break;
  409. case WHAT_LINE_TIMES:
  410. if ((c = fgetc(self->logfp)) == EOF)
  411. err = ERR_EOF;
  412. else {
  413. self->linetimings = c ? 1 : 0;
  414. goto restart;
  415. }
  416. break;
  417. case WHAT_FRAME_TIMES:
  418. if ((c = fgetc(self->logfp)) == EOF)
  419. err = ERR_EOF;
  420. else {
  421. self->frametimings = c ? 1 : 0;
  422. goto restart;
  423. }
  424. break;
  425. default:
  426. err = ERR_BAD_RECTYPE;
  427. }
  428. if (err == ERR_BAD_RECTYPE) {
  429. PyErr_SetString(PyExc_ValueError,
  430. "unknown record type in log file");
  431. }
  432. else if (err == ERR_EOF) {
  433. eof_error(self);
  434. }
  435. else if (!err) {
  436. result = PyTuple_New(4);
  437. if (result == NULL)
  438. return NULL;
  439. PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what));
  440. PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno));
  441. if (s1 == NULL)
  442. PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta));
  443. else
  444. PyTuple_SET_ITEM(result, 1, s1);
  445. if (s2 == NULL)
  446. PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno));
  447. else
  448. PyTuple_SET_ITEM(result, 3, s2);
  449. }
  450. /* The only other case is err == ERR_EXCEPTION, in which case the
  451. * exception is already set.
  452. */
  453. #if 0
  454. b0 = self->buffer[self->index];
  455. b1 = self->buffer[self->index + 1];
  456. if (b0 & 1) {
  457. /* This is a line-number event. */
  458. what = PyTrace_LINE;
  459. lineno = ((b0 & ~1) << 7) + b1;
  460. self->index += 2;
  461. }
  462. else {
  463. what = (b0 & 0x0E) >> 1;
  464. tdelta = ((b0 & 0xF0) << 4) + b1;
  465. if (what == PyTrace_CALL) {
  466. /* we know there's a 2-byte file ID & 2-byte line number */
  467. fileno = ((self->buffer[self->index + 2] << 8)
  468. + self->buffer[self->index + 3]);
  469. lineno = ((self->buffer[self->index + 4] << 8)
  470. + self->buffer[self->index + 5]);
  471. self->index += 6;
  472. }
  473. else
  474. self->index += 2;
  475. }
  476. #endif
  477. return result;
  478. }
  479. static void
  480. logreader_dealloc(LogReaderObject *self)
  481. {
  482. if (self->logfp != NULL) {
  483. fclose(self->logfp);
  484. self->logfp = NULL;
  485. }
  486. Py_XDECREF(self->info);
  487. PyObject_Del(self);
  488. }
  489. static PyObject *
  490. logreader_sq_item(LogReaderObject *self, Py_ssize_t index)
  491. {
  492. PyObject *result = logreader_tp_iternext(self);
  493. if (result == NULL && !PyErr_Occurred()) {
  494. PyErr_SetString(PyExc_IndexError, "no more events in log");
  495. return NULL;
  496. }
  497. return result;
  498. }
  499. static void
  500. do_stop(ProfilerObject *self);
  501. static int
  502. flush_data(ProfilerObject *self)
  503. {
  504. /* Need to dump data to the log file... */
  505. size_t written = fwrite(self->buffer, 1, self->index, self->logfp);
  506. if (written == (size_t)self->index)
  507. self->index = 0;
  508. else {
  509. memmove(self->buffer, &self->buffer[written],
  510. self->index - written);
  511. self->index -= written;
  512. if (written == 0) {
  513. char *s = PyString_AsString(self->logfilename);
  514. PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
  515. do_stop(self);
  516. return -1;
  517. }
  518. }
  519. if (written > 0) {
  520. if (fflush(self->logfp)) {
  521. char *s = PyString_AsString(self->logfilename);
  522. PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
  523. do_stop(self);
  524. return -1;
  525. }
  526. }
  527. return 0;
  528. }
  529. static inline int
  530. pack_packed_int(ProfilerObject *self, int value)
  531. {
  532. unsigned char partial;
  533. do {
  534. partial = value & 0x7F;
  535. value >>= 7;
  536. if (value)
  537. partial |= 0x80;
  538. self->buffer[self->index] = partial;
  539. self->index++;
  540. } while (value);
  541. return 0;
  542. }
  543. /* Encode a modified packed integer, with a subfield of modsize bits
  544. * containing the value "subfield". The value of subfield is not
  545. * checked to ensure it actually fits in modsize bits.
  546. */
  547. static inline int
  548. pack_modified_packed_int(ProfilerObject *self, int value,
  549. int modsize, int subfield)
  550. {
  551. const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127};
  552. int bits = 7 - modsize;
  553. int partial = value & maxvalues[bits];
  554. unsigned char b = subfield | (partial << modsize);
  555. if (partial != value) {
  556. b |= 0x80;
  557. self->buffer[self->index] = b;
  558. self->index++;
  559. return pack_packed_int(self, value >> bits);
  560. }
  561. self->buffer[self->index] = b;
  562. self->index++;
  563. return 0;
  564. }
  565. static int
  566. pack_string(ProfilerObject *self, const char *s, Py_ssize_t len)
  567. {
  568. if (len + PISIZE + self->index >= BUFFERSIZE) {
  569. if (flush_data(self) < 0)
  570. return -1;
  571. }
  572. assert(len < INT_MAX);
  573. if (pack_packed_int(self, (int)len) < 0)
  574. return -1;
  575. memcpy(self->buffer + self->index, s, len);
  576. self->index += len;
  577. return 0;
  578. }
  579. static int
  580. pack_add_info(ProfilerObject *self, const char *s1, const char *s2)
  581. {
  582. Py_ssize_t len1 = strlen(s1);
  583. Py_ssize_t len2 = strlen(s2);
  584. if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
  585. if (flush_data(self) < 0)
  586. return -1;
  587. }
  588. self->buffer[self->index] = WHAT_ADD_INFO;
  589. self->index++;
  590. if (pack_string(self, s1, len1) < 0)
  591. return -1;
  592. return pack_string(self, s2, len2);
  593. }
  594. static int
  595. pack_define_file(ProfilerObject *self, int fileno, const char *filename)
  596. {
  597. Py_ssize_t len = strlen(filename);
  598. if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
  599. if (flush_data(self) < 0)
  600. return -1;
  601. }
  602. self->buffer[self->index] = WHAT_DEFINE_FILE;
  603. self->index++;
  604. if (pack_packed_int(self, fileno) < 0)
  605. return -1;
  606. return pack_string(self, filename, len);
  607. }
  608. static int
  609. pack_define_func(ProfilerObject *self, int fileno, int lineno,
  610. const char *funcname)
  611. {
  612. Py_ssize_t len = strlen(funcname);
  613. if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) {
  614. if (flush_data(self) < 0)
  615. return -1;
  616. }
  617. self->buffer[self->index] = WHAT_DEFINE_FUNC;
  618. self->index++;
  619. if (pack_packed_int(self, fileno) < 0)
  620. return -1;
  621. if (pack_packed_int(self, lineno) < 0)
  622. return -1;
  623. return pack_string(self, funcname, len);
  624. }
  625. static int
  626. pack_line_times(ProfilerObject *self)
  627. {
  628. if (2 + self->index >= BUFFERSIZE) {
  629. if (flush_data(self) < 0)
  630. return -1;
  631. }
  632. self->buffer[self->index] = WHAT_LINE_TIMES;
  633. self->buffer[self->index + 1] = self->linetimings ? 1 : 0;
  634. self->index += 2;
  635. return 0;
  636. }
  637. static int
  638. pack_frame_times(ProfilerObject *self)
  639. {
  640. if (2 + self->index >= BUFFERSIZE) {
  641. if (flush_data(self) < 0)
  642. return -1;
  643. }
  644. self->buffer[self->index] = WHAT_FRAME_TIMES;
  645. self->buffer[self->index + 1] = self->frametimings ? 1 : 0;
  646. self->index += 2;
  647. return 0;
  648. }
  649. static inline int
  650. pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno)
  651. {
  652. if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) {
  653. if (flush_data(self) < 0)
  654. return -1;
  655. }
  656. pack_modified_packed_int(self, fileno, 2, WHAT_ENTER);
  657. pack_packed_int(self, lineno);
  658. if (self->frametimings)
  659. return pack_packed_int(self, tdelta);
  660. else
  661. return 0;
  662. }
  663. static inline int
  664. pack_exit(ProfilerObject *self, int tdelta)
  665. {
  666. if (MPISIZE + self->index >= BUFFERSIZE) {
  667. if (flush_data(self) < 0)
  668. return -1;
  669. }
  670. if (self->frametimings)
  671. return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT);
  672. self->buffer[self->index] = WHAT_EXIT;
  673. self->index++;
  674. return 0;
  675. }
  676. static inline int
  677. pack_lineno(ProfilerObject *self, int lineno)
  678. {
  679. if (MPISIZE + self->index >= BUFFERSIZE) {
  680. if (flush_data(self) < 0)
  681. return -1;
  682. }
  683. return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO);
  684. }
  685. static inline int
  686. pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta)
  687. {
  688. if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) {
  689. if (flush_data(self) < 0)
  690. return 0;
  691. }
  692. if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0)
  693. return -1;
  694. return pack_packed_int(self, tdelta);
  695. }
  696. static inline int
  697. get_fileno(ProfilerObject *self, PyCodeObject *fcode)
  698. {
  699. /* This is only used for ENTER events. */
  700. PyObject *obj;
  701. PyObject *dict;
  702. int fileno;
  703. obj = PyDict_GetItem(self->filemap, fcode->co_filename);
  704. if (obj == NULL) {
  705. /* first sighting of this file */
  706. dict = PyDict_New();
  707. if (dict == NULL) {
  708. return -1;
  709. }
  710. fileno = self->next_fileno;
  711. obj = Py_BuildValue("iN", fileno, dict);
  712. if (obj == NULL) {
  713. return -1;
  714. }
  715. if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) {
  716. Py_DECREF(obj);
  717. return -1;
  718. }
  719. self->next_fileno++;
  720. Py_DECREF(obj);
  721. if (pack_define_file(self, fileno,
  722. PyString_AS_STRING(fcode->co_filename)) < 0)
  723. return -1;
  724. }
  725. else {
  726. /* already know this ID */
  727. fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0));
  728. dict = PyTuple_GET_ITEM(obj, 1);
  729. }
  730. /* make sure we save a function name for this (fileno, lineno) */
  731. obj = PyInt_FromLong(fcode->co_firstlineno);
  732. if (obj == NULL) {
  733. /* We just won't have it saved; too bad. */
  734. PyErr_Clear();
  735. }
  736. else {
  737. PyObject *name = PyDict_GetItem(dict, obj);
  738. if (name == NULL) {
  739. if (pack_define_func(self, fileno, fcode->co_firstlineno,
  740. PyString_AS_STRING(fcode->co_name)) < 0) {
  741. Py_DECREF(obj);
  742. return -1;
  743. }
  744. if (PyDict_SetItem(dict, obj, fcode->co_name)) {
  745. Py_DECREF(obj);
  746. return -1;
  747. }
  748. }
  749. Py_DECREF(obj);
  750. }
  751. return fileno;
  752. }
  753. static inline int
  754. get_tdelta(ProfilerObject *self)
  755. {
  756. int tdelta;
  757. #ifdef MS_WINDOWS
  758. hs_time tv;
  759. hs_time diff;
  760. GETTIMEOFDAY(&tv);
  761. diff = tv - self->prev_timeofday;
  762. tdelta = (int)diff;
  763. #else
  764. struct timeval tv;
  765. GETTIMEOFDAY(&tv);
  766. tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
  767. if (tv.tv_sec != self->prev_timeofday.tv_sec)
  768. tdelta += (tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000;
  769. #endif
  770. /* time can go backwards on some multiprocessor systems or by NTP */
  771. if (tdelta < 0)
  772. return 0;
  773. self->prev_timeofday = tv;
  774. return tdelta;
  775. }
  776. /* The workhorse: the profiler callback function. */
  777. static int
  778. tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
  779. PyObject *arg)
  780. {
  781. int fileno;
  782. switch (what) {
  783. case PyTrace_CALL:
  784. fileno = get_fileno(self, frame->f_code);
  785. if (fileno < 0)
  786. return -1;
  787. return pack_enter(self, fileno,
  788. self->frametimings ? get_tdelta(self) : -1,
  789. frame->f_code->co_firstlineno);
  790. case PyTrace_RETURN:
  791. return pack_exit(self, get_tdelta(self));
  792. case PyTrace_LINE: /* we only get these events if we asked for them */
  793. if (self->linetimings)
  794. return pack_lineno_tdelta(self, frame->f_lineno,
  795. get_tdelta(self));
  796. else
  797. return pack_lineno(self, frame->f_lineno);
  798. default:
  799. /* ignore PyTrace_EXCEPTION */
  800. break;
  801. }
  802. return 0;
  803. }
  804. /* A couple of useful helper functions. */
  805. #ifdef MS_WINDOWS
  806. static LARGE_INTEGER frequency = {0, 0};
  807. #endif
  808. static unsigned long timeofday_diff = 0;
  809. static unsigned long rusage_diff = 0;
  810. static void
  811. calibrate(void)
  812. {
  813. hs_time tv1, tv2;
  814. #ifdef MS_WINDOWS
  815. hs_time diff;
  816. QueryPerformanceFrequency(&frequency);
  817. #endif
  818. GETTIMEOFDAY(&tv1);
  819. while (1) {
  820. GETTIMEOFDAY(&tv2);
  821. #ifdef MS_WINDOWS
  822. diff = tv2 - tv1;
  823. if (diff != 0) {
  824. timeofday_diff = (unsigned long)diff;
  825. break;
  826. }
  827. #else
  828. if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
  829. if (tv1.tv_sec == tv2.tv_sec)
  830. timeofday_diff = tv2.tv_usec - tv1.tv_usec;
  831. else
  832. timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
  833. break;
  834. }
  835. #endif
  836. }
  837. #if defined(MS_WINDOWS) || defined(PYOS_OS2) || \
  838. defined(__VMS) || defined (__QNX__)
  839. rusage_diff = -1;
  840. #else
  841. {
  842. struct rusage ru1, ru2;
  843. getrusage(RUSAGE_SELF, &ru1);
  844. while (1) {
  845. getrusage(RUSAGE_SELF, &ru2);
  846. if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
  847. rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
  848. + ru2.ru_utime.tv_usec);
  849. break;
  850. }
  851. else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
  852. rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
  853. break;
  854. }
  855. else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
  856. rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
  857. + ru2.ru_stime.tv_usec);
  858. break;
  859. }
  860. else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
  861. rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
  862. break;
  863. }
  864. }
  865. }
  866. #endif
  867. }
  868. static void
  869. do_start(ProfilerObject *self)
  870. {
  871. self->active = 1;
  872. GETTIMEOFDAY(&self->prev_timeofday);
  873. if (self->lineevents)
  874. PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
  875. else
  876. PyEval_SetProfile((Py_tracefunc) tracer_callback, (PyObject *)self);
  877. }
  878. static void
  879. do_stop(ProfilerObject *self)
  880. {
  881. if (self->active) {
  882. self->active = 0;
  883. if (self->lineevents)
  884. PyEval_SetTrace(NULL, NULL);
  885. else
  886. PyEval_SetProfile(NULL, NULL);
  887. }
  888. if (self->index > 0) {
  889. /* Best effort to dump out any remaining data. */
  890. flush_data(self);
  891. }
  892. }
  893. static int
  894. is_available(ProfilerObject *self)
  895. {
  896. if (self->active) {
  897. PyErr_SetString(ProfilerError, "profiler already active");
  898. return 0;
  899. }
  900. if (self->logfp == NULL) {
  901. PyErr_SetString(ProfilerError, "profiler already closed");
  902. return 0;
  903. }
  904. return 1;
  905. }
  906. /* Profiler object interface methods. */
  907. PyDoc_STRVAR(addinfo__doc__,
  908. "addinfo(key, value)\n"
  909. "Insert an ADD_INFO record into the log.");
  910. static PyObject *
  911. profiler_addinfo(ProfilerObject *self, PyObject *args)
  912. {
  913. PyObject *result = NULL;
  914. char *key, *value;
  915. if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
  916. if (self->logfp == NULL)
  917. PyErr_SetString(ProfilerError, "profiler already closed");
  918. else {
  919. if (pack_add_info(self, key, value) == 0) {
  920. result = Py_None;
  921. Py_INCREF(result);
  922. }
  923. }
  924. }
  925. return result;
  926. }
  927. PyDoc_STRVAR(close__doc__,
  928. "close()\n"
  929. "Shut down this profiler and close the log files, even if its active.");
  930. static PyObject *
  931. profiler_close(ProfilerObject *self)
  932. {
  933. do_stop(self);
  934. if (self->logfp != NULL) {
  935. fclose(self->logfp);
  936. self->logfp = NULL;
  937. }
  938. Py_INCREF(Py_None);
  939. return Py_None;
  940. }
  941. #define fileno__doc__ logreader_fileno__doc__
  942. static PyObject *
  943. profiler_fileno(ProfilerObject *self)
  944. {
  945. if (self->logfp == NULL) {
  946. PyErr_SetString(PyExc_ValueError,
  947. "profiler's file object already closed");
  948. return NULL;
  949. }
  950. return PyInt_FromLong(fileno(self->logfp));
  951. }
  952. PyDoc_STRVAR(runcall__doc__,
  953. "runcall(callable[, args[, kw]]) -> callable()\n"
  954. "Profile a specific function call, returning the result of that call.");
  955. static PyObject *
  956. profiler_runcall(ProfilerObject *self, PyObject *args)
  957. {
  958. PyObject *result = NULL;
  959. PyObject *callargs = NULL;
  960. PyObject *callkw = NULL;
  961. PyObject *callable;
  962. if (PyArg_UnpackTuple(args, "runcall", 1, 3,
  963. &callable, &callargs, &callkw)) {
  964. if (is_available(self)) {
  965. do_start(self);
  966. result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
  967. do_stop(self);
  968. }
  969. }
  970. return result;
  971. }
  972. PyDoc_STRVAR(runcode__doc__,
  973. "runcode(code, globals[, locals])\n"
  974. "Execute a code object while collecting profile data. If locals is\n"
  975. "omitted, globals is used for the locals as well.");
  976. static PyObject *
  977. profiler_runcode(ProfilerObject *self, PyObject *args)
  978. {
  979. PyObject *result = NULL;
  980. PyCodeObject *code;
  981. PyObject *globals;
  982. PyObject *locals = NULL;
  983. if (PyArg_ParseTuple(args, "O!O!|O:runcode",
  984. &PyCode_Type, &code,
  985. &PyDict_Type, &globals,
  986. &locals)) {
  987. if (is_available(self)) {
  988. if (locals == NULL || locals == Py_None)
  989. locals = globals;
  990. else if (!PyDict_Check(locals)) {
  991. PyErr_SetString(PyExc_TypeError,
  992. "locals must be a dictionary or None");
  993. return NULL;
  994. }
  995. do_start(self);
  996. result = PyEval_EvalCode(code, globals, locals);
  997. do_stop(self);
  998. #if 0
  999. if (!PyErr_Occurred()) {
  1000. result = Py_None;
  1001. Py_INCREF(result);
  1002. }
  1003. #endif
  1004. }
  1005. }
  1006. return result;
  1007. }
  1008. PyDoc_STRVAR(start__doc__,
  1009. "start()\n"
  1010. "Install this profiler for the current thread.");
  1011. static PyObject *
  1012. profiler_start(ProfilerObject *self, PyObject *args)
  1013. {
  1014. PyObject *result = NULL;
  1015. if (is_available(self)) {
  1016. do_start(self);
  1017. result = Py_None;
  1018. Py_INCREF(result);
  1019. }
  1020. return result;
  1021. }
  1022. PyDoc_STRVAR(stop__doc__,
  1023. "stop()\n"
  1024. "Remove this profiler from the current thread.");
  1025. static PyObject *
  1026. profiler_stop(ProfilerObject *self, PyObject *args)
  1027. {
  1028. PyObject *result = NULL;
  1029. if (!self->active)
  1030. PyErr_SetString(ProfilerError, "profiler not active");
  1031. else {
  1032. do_stop(self);
  1033. result = Py_None;
  1034. Py_INCREF(result);
  1035. }
  1036. return result;
  1037. }
  1038. /* Python API support. */
  1039. static void
  1040. profiler_dealloc(ProfilerObject *self)
  1041. {
  1042. do_stop(self);
  1043. if (self->logfp != NULL)
  1044. fclose(self->logfp);
  1045. Py_XDECREF(self->filemap);
  1046. Py_XDECREF(self->logfilename);
  1047. PyObject_Del((PyObject *)self);
  1048. }
  1049. static PyMethodDef profiler_methods[] = {
  1050. {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
  1051. {"close", (PyCFunction)profiler_close, METH_NOARGS, close__doc__},
  1052. {"fileno", (PyCFunction)profiler_fileno, METH_NOARGS, fileno__doc__},
  1053. {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
  1054. {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
  1055. {"start", (PyCFunction)profiler_start, METH_NOARGS, start__doc__},
  1056. {"stop", (PyCFunction)profiler_stop, METH_NOARGS, stop__doc__},
  1057. {NULL, NULL}
  1058. };
  1059. static PyMemberDef profiler_members[] = {
  1060. {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
  1061. {"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
  1062. {"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
  1063. {NULL}
  1064. };
  1065. static PyObject *
  1066. profiler_get_closed(ProfilerObject *self, void *closure)
  1067. {
  1068. PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
  1069. Py_INCREF(result);
  1070. return result;
  1071. }
  1072. static PyGetSetDef profiler_getsets[] = {
  1073. {"closed", (getter)profiler_get_closed, NULL,
  1074. PyDoc_STR("True if the profiler's output file has already been closed.")},
  1075. {NULL}
  1076. };
  1077. PyDoc_STRVAR(profiler_object__doc__,
  1078. "High-performance profiler object.\n"
  1079. "\n"
  1080. "Methods:\n"
  1081. "\n"
  1082. "close(): Stop the profiler and close the log files.\n"
  1083. "fileno(): Returns the file descriptor of the log file.\n"
  1084. "runcall(): Run a single function call with profiling enabled.\n"
  1085. "runcode(): Execute a code object with profiling enabled.\n"
  1086. "start(): Install the profiler and return.\n"
  1087. "stop(): Remove the profiler.\n"
  1088. "\n"
  1089. "Attributes (read-only):\n"
  1090. "\n"
  1091. "closed: True if the profiler has already been closed.\n"
  1092. "frametimings: True if ENTER/EXIT events collect timing information.\n"
  1093. "lineevents: True if line events are reported to the profiler.\n"
  1094. "linetimings: True if line events collect timing information.");
  1095. static PyTypeObject ProfilerType = {
  1096. PyVarObject_HEAD_INIT(NULL, 0)
  1097. "_hotshot.ProfilerType", /* tp_name */
  1098. (int) sizeof(ProfilerObject), /* tp_basicsize */
  1099. 0, /* tp_itemsize */
  1100. (destructor)profiler_dealloc, /* tp_dealloc */
  1101. 0, /* tp_print */
  1102. 0, /* tp_getattr */
  1103. 0, /* tp_setattr */
  1104. 0, /* tp_compare */
  1105. 0, /* tp_repr */
  1106. 0, /* tp_as_number */
  1107. 0, /* tp_as_sequence */
  1108. 0, /* tp_as_mapping */
  1109. 0, /* tp_hash */
  1110. 0, /* tp_call */
  1111. 0, /* tp_str */
  1112. PyObject_GenericGetAttr, /* tp_getattro */
  1113. 0, /* tp_setattro */
  1114. 0, /* tp_as_buffer */
  1115. Py_TPFLAGS_DEFAULT, /* tp_flags */
  1116. profiler_object__doc__, /* tp_doc */
  1117. 0, /* tp_traverse */
  1118. 0, /* tp_clear */
  1119. 0, /* tp_richcompare */
  1120. 0, /* tp_weaklistoffset */
  1121. 0, /* tp_iter */
  1122. 0, /* tp_iternext */
  1123. profiler_methods, /* tp_methods */
  1124. profiler_members, /* tp_members */
  1125. profiler_getsets, /* tp_getset */
  1126. 0, /* tp_base */
  1127. 0, /* tp_dict */
  1128. 0, /* tp_descr_get */
  1129. 0, /* tp_descr_set */
  1130. };
  1131. static PyMethodDef logreader_methods[] = {
  1132. {"close", (PyCFunction)logreader_close, METH_NOARGS,
  1133. logreader_close__doc__},
  1134. {"fileno", (PyCFunction)logreader_fileno, METH_NOARGS,
  1135. logreader_fileno__doc__},
  1136. {NULL, NULL}
  1137. };
  1138. static PyMemberDef logreader_members[] = {
  1139. {"info", T_OBJECT, offsetof(LogReaderObject, info), RO,
  1140. PyDoc_STR("Dictionary mapping informational keys to lists of values.")},
  1141. {NULL}
  1142. };
  1143. PyDoc_STRVAR(logreader__doc__,
  1144. "logreader(filename) --> log-iterator\n\
  1145. Create a log-reader for the timing information file.");
  1146. static PySequenceMethods logreader_as_sequence = {
  1147. 0, /* sq_length */
  1148. 0, /* sq_concat */
  1149. 0, /* sq_repeat */
  1150. (ssizeargfunc)logreader_sq_item, /* sq_item */
  1151. 0, /* sq_slice */
  1152. 0, /* sq_ass_item */
  1153. 0, /* sq_ass_slice */
  1154. 0, /* sq_contains */
  1155. 0, /* sq_inplace_concat */
  1156. 0, /* sq_inplace_repeat */
  1157. };
  1158. static PyObject *
  1159. logreader_get_closed(LogReaderObject *self, void *closure)
  1160. {
  1161. PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
  1162. Py_INCREF(result);
  1163. return result;
  1164. }
  1165. static PyGetSetDef logreader_getsets[] = {
  1166. {"closed", (getter)logreader_get_closed, NULL,
  1167. PyDoc_STR("True if the logreader's input file has already been closed.")},
  1168. {NULL}
  1169. };
  1170. static PyTypeObject LogReaderType = {
  1171. PyVarObject_HEAD_INIT(NULL, 0)
  1172. "_hotshot.LogReaderType", /* tp_name */
  1173. (int) sizeof(LogReaderObject), /* tp_basicsize */
  1174. 0, /* tp_itemsize */
  1175. (destructor)logreader_dealloc, /* tp_dealloc */
  1176. 0, /* tp_print */
  1177. 0, /* tp_getattr */
  1178. 0, /* tp_setattr */
  1179. 0, /* tp_compare */
  1180. 0, /* tp_repr */
  1181. 0, /* tp_as_number */
  1182. &logreader_as_sequence, /* tp_as_sequence */
  1183. 0, /* tp_as_mapping */
  1184. 0, /* tp_hash */
  1185. 0, /* tp_call */
  1186. 0, /* tp_str */
  1187. PyObject_GenericGetAttr, /* tp_getattro */
  1188. 0, /* tp_setattro */
  1189. 0, /* tp_as_buffer */
  1190. Py_TPFLAGS_DEFAULT, /* tp_flags */
  1191. logreader__doc__, /* tp_doc */
  1192. 0, /* tp_traverse */
  1193. 0, /* tp_clear */
  1194. 0, /* tp_richcompare */
  1195. 0, /* tp_weaklistoffset */
  1196. PyObject_SelfIter, /* tp_iter */
  1197. (iternextfunc)logreader_tp_iternext,/* tp_iternext */
  1198. logreader_methods, /* tp_methods */
  1199. logreader_members, /* tp_members */
  1200. logreader_getsets, /* tp_getset */
  1201. 0, /* tp_base */
  1202. 0, /* tp_dict */
  1203. 0, /* tp_descr_get */
  1204. 0, /* tp_descr_set */
  1205. };
  1206. static PyObject *
  1207. hotshot_logreader(PyObject *unused, PyObject *args)
  1208. {
  1209. LogReaderObject *self = NULL;
  1210. char *filename;
  1211. int c;
  1212. int err = 0;
  1213. if (PyArg_ParseTuple(args, "s:logreader", &filename)) {
  1214. self = PyObject_New(LogReaderObject, &LogReaderType);
  1215. if (self != NULL) {
  1216. self->frametimings = 1;
  1217. self->linetimings = 0;
  1218. self->info = NULL;
  1219. self->logfp = fopen(filename, "rb");
  1220. if (self->logfp == NULL) {
  1221. PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
  1222. goto error;
  1223. }
  1224. self->info = PyDict_New();
  1225. if (self->info == NULL)
  1226. goto error;
  1227. /* read initial info */
  1228. for (;;) {
  1229. if ((c = fgetc(self->logfp)) == EOF) {
  1230. eof_error(self);
  1231. goto error;
  1232. }
  1233. if (c != WHAT_ADD_INFO) {
  1234. ungetc(c, self->logfp);
  1235. break;
  1236. }
  1237. err = unpack_add_info(self);
  1238. if (err) {
  1239. if (err == ERR_EOF)
  1240. eof_error(self);
  1241. else
  1242. PyErr_SetString(PyExc_RuntimeError,
  1243. "unexpected error");
  1244. goto error;
  1245. }
  1246. }
  1247. }
  1248. }
  1249. return (PyObject *) self;
  1250. error:
  1251. Py_DECREF(self);
  1252. return NULL;
  1253. }
  1254. /* Return a Python string that represents the version number without the
  1255. * extra cruft added by revision control, even if the right options were
  1256. * given to the "cvs export" command to make it not include the extra
  1257. * cruft.
  1258. */
  1259. static char *
  1260. get_version_string(void)
  1261. {
  1262. static char *rcsid = "$Revision: 67801 $";
  1263. char *rev = rcsid;
  1264. char *buffer;
  1265. int i = 0;
  1266. while (*rev && !isdigit(Py_CHARMASK(*rev)))
  1267. ++rev;
  1268. while (rev[i] != ' ' && rev[i] != '\0')
  1269. ++i;
  1270. buffer = (char *)malloc(i + 1);
  1271. if (buffer != NULL) {
  1272. memmove(buffer, rev, i);
  1273. buffer[i] = '\0';
  1274. }
  1275. return buffer;
  1276. }
  1277. /* Write out a RFC 822-style header with various useful bits of
  1278. * information to make the output easier to manage.
  1279. */
  1280. static int
  1281. write_header(ProfilerObject *self)
  1282. {
  1283. char *buffer;
  1284. char cwdbuffer[PATH_MAX];
  1285. PyObject *temp;
  1286. Py_ssize_t i, len;
  1287. buffer = get_version_string();
  1288. if (buffer == NULL) {
  1289. PyErr_NoMemory();
  1290. return -1;
  1291. }
  1292. pack_add_info(self, "hotshot-version", buffer);
  1293. pack_add_info(self, "requested-frame-timings",
  1294. (self->frametimings ? "yes" : "no"));
  1295. pack_add_info(self, "requested-line-events",
  1296. (self->lineevents ? "yes" : "no"));
  1297. pack_add_info(self, "requested-line-timings",
  1298. (self->linetimings ? "yes" : "no"));
  1299. pack_add_info(self, "platform", Py_GetPlatform());
  1300. pack_add_info(self, "executable", Py_GetProgramFullPath());
  1301. free(buffer);
  1302. buffer = (char *) Py_GetVersion();
  1303. if (buffer == NULL)
  1304. PyErr_Clear();
  1305. else
  1306. pack_add_info(self, "executable-version", buffer);
  1307. #ifdef MS_WINDOWS
  1308. PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart);
  1309. pack_add_info(self, "reported-performance-frequency", cwdbuffer);
  1310. #else
  1311. PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff);
  1312. pack_add_info(self, "observed-interval-getrusage", cwdbuffer);
  1313. PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff);
  1314. pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer);
  1315. #endif
  1316. pack_add_info(self, "current-directory",
  1317. getcwd(cwdbuffer, sizeof cwdbuffer));
  1318. temp = PySys_GetObject("path");
  1319. if (temp == NULL || !PyList_Check(temp)) {
  1320. PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list");
  1321. return -1;
  1322. }
  1323. len = PyList_GET_SIZE(temp);
  1324. for (i = 0; i < len; ++i) {
  1325. PyObject *item = PyList_GET_ITEM(temp, i);
  1326. buffer = PyString_AsString(item);
  1327. if (buffer == NULL) {
  1328. pack_add_info(self, "sys-path-entry", "<non-string-path-entry>");
  1329. PyErr_Clear();
  1330. }
  1331. else {
  1332. pack_add_info(self, "sys-path-entry", buffer);
  1333. }
  1334. }
  1335. pack_frame_times(self);
  1336. pack_line_times(self);
  1337. return 0;
  1338. }
  1339. PyDoc_STRVAR(profiler__doc__,
  1340. "profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
  1341. Create a new profiler object.");
  1342. static PyObject *
  1343. hotshot_profiler(PyObject *unused, PyObject *args)
  1344. {
  1345. char *logfilename;
  1346. ProfilerObject *self = NULL;
  1347. int lineevents = 0;
  1348. int linetimings = 1;
  1349. if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename,
  1350. &lineevents, &linetimings)) {
  1351. self = PyObject_New(ProfilerObject, &ProfilerType);
  1352. if (self == NULL)
  1353. return NULL;
  1354. self->frametimings = 1;
  1355. self->lineevents = lineevents ? 1 : 0;
  1356. self->linetimings = (lineevents && linetimings) ? 1 : 0;
  1357. self->index = 0;
  1358. self->active = 0;
  1359. self->next_fileno = 0;
  1360. self->logfp = NULL;
  1361. self->logfilename = PyTuple_GET_ITEM(args, 0);
  1362. Py_INCREF(self->logfilename);
  1363. self->filemap = PyDict_New();
  1364. if (self->filemap == NULL) {
  1365. Py_DECREF(self);
  1366. return NULL;
  1367. }
  1368. self->logfp = fopen(logfilename, "wb");
  1369. if (self->logfp == NULL) {
  1370. Py_DECREF(self);
  1371. PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename);
  1372. return NULL;
  1373. }
  1374. if (timeofday_diff == 0) {
  1375. /* Run this several times since sometimes the first
  1376. * doesn't give the lowest values, and we're really trying
  1377. * to determine the lowest.
  1378. */
  1379. calibrate();
  1380. calibrate();
  1381. calibrate();
  1382. }
  1383. if (write_header(self)) {
  1384. /* some error occurred, exception has been set */
  1385. Py_DECREF(self);
  1386. self = NULL;
  1387. }
  1388. }
  1389. return (PyObject *) self;
  1390. }
  1391. PyDoc_STRVAR(coverage__doc__,
  1392. "coverage(logfilename) -> profiler\n\
  1393. Returns a profiler that doesn't collect any timing information, which is\n\
  1394. useful in building a coverage analysis tool.");
  1395. static PyObject *
  1396. hotshot_coverage(PyObject *unused, PyObject *args)
  1397. {
  1398. char *logfilename;
  1399. PyObject *result = NULL;
  1400. if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) {
  1401. result = hotshot_profiler(unused, args);
  1402. if (result != NULL) {
  1403. ProfilerObject *self = (ProfilerObject *) result;
  1404. self->frametimings = 0;
  1405. self->linetimings = 0;
  1406. self->lineevents = 1;
  1407. }
  1408. }
  1409. return result;
  1410. }
  1411. PyDoc_VAR(resolution__doc__) =
  1412. #ifdef MS_WINDOWS
  1413. PyDoc_STR(
  1414. "resolution() -> (performance-counter-ticks, update-frequency)\n"
  1415. "Return the resolution of the timer provided by the QueryPerformanceCounter()\n"
  1416. "function. The first value is the smallest observed change, and the second\n"
  1417. "is the result of QueryPerformanceFrequency()."
  1418. )
  1419. #else
  1420. PyDoc_STR(
  1421. "resolution() -> (gettimeofday-usecs, getrusage-usecs)\n"
  1422. "Return the resolution of the timers provided by the gettimeofday() and\n"
  1423. "getrusage() system calls, or -1 if the call is not supported."
  1424. )
  1425. #endif
  1426. ;
  1427. static PyObject *
  1428. hotshot_resolution(PyObject *self, PyObject *unused)
  1429. {
  1430. if (timeofday_diff == 0) {
  1431. calibrate();
  1432. calibrate();
  1433. calibrate();
  1434. }
  1435. #ifdef MS_WINDOWS
  1436. return Py_BuildValue("ii", timeofday_diff, frequency.LowPart);
  1437. #else
  1438. return Py_BuildValue("ii", timeofday_diff, rusage_diff);
  1439. #endif
  1440. }
  1441. static PyMethodDef functions[] = {
  1442. {"coverage", hotshot_coverage, METH_VARARGS, coverage__doc__},
  1443. {"profiler", hotshot_profiler, METH_VARARGS, profiler__doc__},
  1444. {"logreader", hotshot_logreader, METH_VARARGS, logreader__doc__},
  1445. {"resolution", hotshot_resolution, METH_NOARGS, resolution__doc__},
  1446. {NULL, NULL}
  1447. };
  1448. void
  1449. init_hotshot(void)
  1450. {
  1451. PyObject *module;
  1452. Py_TYPE(&LogReaderType) = &PyType_Type;
  1453. Py_TYPE(&ProfilerType) = &PyType_Type;
  1454. module = Py_InitModule("_hotshot", functions);
  1455. if (module != NULL) {
  1456. char *s = get_version_string();
  1457. PyModule_AddStringConstant(module, "__version__", s);
  1458. free(s);
  1459. Py_INCREF(&LogReaderType);
  1460. PyModule_AddObject(module, "LogReaderType",
  1461. (PyObject *)&LogReaderType);
  1462. Py_INCREF(&ProfilerType);
  1463. PyModule_AddObject(module, "ProfilerType",
  1464. (PyObject *)&ProfilerType);
  1465. if (ProfilerError == NULL)
  1466. ProfilerError = PyErr_NewException("hotshot.ProfilerError",
  1467. NULL, NULL);
  1468. if (ProfilerError != NULL) {
  1469. Py_INCREF(ProfilerError);
  1470. PyModule_AddObject(module, "ProfilerError", ProfilerError);
  1471. }
  1472. PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER);
  1473. PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT);
  1474. PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO);
  1475. PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER);
  1476. PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO);
  1477. PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE);
  1478. PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC);
  1479. PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES);
  1480. }
  1481. }