mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00

-DCALL_PROFILE: Count the number of function calls executed. When this symbol is defined, the ceval mainloop and helper functions count the number of function calls made. It keeps detailed statistics about what kind of object was called and whether the call hit any of the special fast paths in the code. Optimization: When we take the fast_function() path, which seems to be taken for most function calls, and there is minimal frame setup to do, avoid call PyEval_EvalCodeEx(). The eval code ex function does a lot of work to handle keywords args and star args, free variables, generators, etc. The inlined version simply allocates the frame and copies the arguments values into the frame. The optimization gets a little help from compile.c which adds a CO_NOFREE flag to code objects that don't have free variables or cell variables. This change allows fast_function() to get into the fast path with fewer tests. I measure a couple of percent speedup in pystone with this change, but there's surely more that can be done.
137 lines
4 KiB
C
137 lines
4 KiB
C
#ifndef Py_CEVAL_H
|
|
#define Py_CEVAL_H
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
/* Interface to random parts in ceval.c */
|
|
|
|
PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords(
|
|
PyObject *, PyObject *, PyObject *);
|
|
|
|
/* DLL-level Backwards compatibility: */
|
|
#undef PyEval_CallObject
|
|
PyAPI_FUNC(PyObject *) PyEval_CallObject(PyObject *, PyObject *);
|
|
|
|
/* Inline this */
|
|
#define PyEval_CallObject(func,arg) \
|
|
PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL)
|
|
|
|
PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *obj, char *format, ...);
|
|
PyAPI_FUNC(PyObject *) PyEval_CallMethod(PyObject *obj,
|
|
char *methodname, char *format, ...);
|
|
|
|
PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *);
|
|
PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *);
|
|
|
|
PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void);
|
|
PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void);
|
|
PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
|
|
PyAPI_FUNC(PyObject *) PyEval_GetOwner(void);
|
|
PyAPI_FUNC(PyObject *) PyEval_GetFrame(void);
|
|
PyAPI_FUNC(int) PyEval_GetRestricted(void);
|
|
|
|
/* Look at the current frame's (if any) code's co_flags, and turn on
|
|
the corresponding compiler flags in cf->cf_flags. Return 1 if any
|
|
flag was set, else return 0. */
|
|
PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
|
|
|
|
PyAPI_FUNC(int) Py_FlushLine(void);
|
|
|
|
PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg);
|
|
PyAPI_FUNC(int) Py_MakePendingCalls(void);
|
|
|
|
PyAPI_FUNC(void) Py_SetRecursionLimit(int);
|
|
PyAPI_FUNC(int) Py_GetRecursionLimit(void);
|
|
|
|
PyAPI_FUNC(char *) PyEval_GetFuncName(PyObject *);
|
|
PyAPI_FUNC(char *) PyEval_GetFuncDesc(PyObject *);
|
|
|
|
PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *);
|
|
|
|
/* this used to be handled on a per-thread basis - now just two globals */
|
|
PyAPI_DATA(volatile int) _Py_Ticker;
|
|
PyAPI_DATA(int) _Py_CheckInterval;
|
|
|
|
/* Interface for threads.
|
|
|
|
A module that plans to do a blocking system call (or something else
|
|
that lasts a long time and doesn't touch Python data) can allow other
|
|
threads to run as follows:
|
|
|
|
...preparations here...
|
|
Py_BEGIN_ALLOW_THREADS
|
|
...blocking system call here...
|
|
Py_END_ALLOW_THREADS
|
|
...interpret result here...
|
|
|
|
The Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS pair expands to a
|
|
{}-surrounded block.
|
|
To leave the block in the middle (e.g., with return), you must insert
|
|
a line containing Py_BLOCK_THREADS before the return, e.g.
|
|
|
|
if (...premature_exit...) {
|
|
Py_BLOCK_THREADS
|
|
PyErr_SetFromErrno(PyExc_IOError);
|
|
return NULL;
|
|
}
|
|
|
|
An alternative is:
|
|
|
|
Py_BLOCK_THREADS
|
|
if (...premature_exit...) {
|
|
PyErr_SetFromErrno(PyExc_IOError);
|
|
return NULL;
|
|
}
|
|
Py_UNBLOCK_THREADS
|
|
|
|
For convenience, that the value of 'errno' is restored across
|
|
Py_END_ALLOW_THREADS and Py_BLOCK_THREADS.
|
|
|
|
WARNING: NEVER NEST CALLS TO Py_BEGIN_ALLOW_THREADS AND
|
|
Py_END_ALLOW_THREADS!!!
|
|
|
|
The function PyEval_InitThreads() should be called only from
|
|
initthread() in "threadmodule.c".
|
|
|
|
Note that not yet all candidates have been converted to use this
|
|
mechanism!
|
|
*/
|
|
|
|
PyAPI_FUNC(PyThreadState *) PyEval_SaveThread(void);
|
|
PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *);
|
|
|
|
#ifdef WITH_THREAD
|
|
|
|
PyAPI_FUNC(void) PyEval_InitThreads(void);
|
|
PyAPI_FUNC(void) PyEval_AcquireLock(void);
|
|
PyAPI_FUNC(void) PyEval_ReleaseLock(void);
|
|
PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate);
|
|
PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate);
|
|
PyAPI_FUNC(void) PyEval_ReInitThreads(void);
|
|
|
|
#define Py_BEGIN_ALLOW_THREADS { \
|
|
PyThreadState *_save; \
|
|
_save = PyEval_SaveThread();
|
|
#define Py_BLOCK_THREADS PyEval_RestoreThread(_save);
|
|
#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread();
|
|
#define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \
|
|
}
|
|
|
|
#else /* !WITH_THREAD */
|
|
|
|
#define Py_BEGIN_ALLOW_THREADS {
|
|
#define Py_BLOCK_THREADS
|
|
#define Py_UNBLOCK_THREADS
|
|
#define Py_END_ALLOW_THREADS }
|
|
|
|
#endif /* !WITH_THREAD */
|
|
|
|
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, int *);
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* !Py_CEVAL_H */
|