Source

hotpy_2 / Include / optimiser.h

/* Optimiser interface */

#ifndef _HOTPY_OPTIMSER_H
#define _HOTPY_OPTIMSER_H

#include "frameobject.h"
#include "trace_opcode.h"
#include "structmember.h"

#define HOTPY_CONTEXT_DEPTH 6

typedef struct _hotpy_instruction_pointer {
    PyCodeObject *code;
    unsigned int offset;
    unsigned int stack;
} HotPyIP;

/* Warning: this evaluates its parameter twice */
#define HotPyIP_ToAddr(ip) \
    ((unsigned char*)PyBytes_AS_STRING((ip).code->co_code) + (ip).offset)

#ifdef Py_DEBUG
int valid_ip_here(unsigned char *ip);
#endif

typedef struct _hotpy_context {
    PyObject_HEAD
    HotPyIP cf_instrs[HOTPY_CONTEXT_DEPTH]; /* 0 is the current frame, 1 its caller, etc. */
    PyObject *cf_deferred_state;
    PyObject *cf_type_info;
    PyObject *cf_constants;
#ifdef Py_DEBUG
    char *cf_name;
#endif
} HotPyContext;

/* why                  value
   WHY_RETURN           (PyObject *)return value
   WHY_EXCEPTION        NULL
   WHY_NOT              (unsigned char*) next instruction */
typedef struct _hotpy_return_value
{
    void *value;
    enum why_code why; /* Can be RETURN, EXCEPTION or NOT */
} HotPyReturnValue;

struct instruction_count {
    char *name;
    unsigned long count;
};

typedef struct _hotpy_stats {
    unsigned long recording;
    unsigned long on_trace;
    unsigned long off_trace;
    unsigned long trace_entries;
    unsigned long trace_transfers;
    unsigned long mono_to_poly;
    unsigned long polymorphic_cold_exits;
    unsigned long polymorphic_overflow_exits;
    unsigned long not_bool_exits;
    unsigned long cold_exits;
    unsigned long exceptions_in_trace;
    unsigned long materialisations;
    unsigned long invalid_exits;
    unsigned long exception_exits;
    unsigned long decays;
    unsigned long trace_cache_size;
#ifdef Py_DEBUG
    struct instruction_count trace_instructions[256];
#endif
    unsigned long failed_trace_recordings;
    unsigned long tracing_frame_stack_overflows;
    unsigned long return_exits;
    unsigned long rare_exits;
    unsigned long materialisation_exits;
} HotPyStatistics;

typedef struct _hotpy_options {
    int decay_interval;
    char show_stats;
    char tracing;
    char log_trace;
    char log_specialiser;
    char log_DOC;
    char specialise;
    char DOC;
    char lltrace;
    char register_vm;
    char coalesce;
    char tailcall;
    char compact;
} HotPyOptions;

typedef struct _hotpy_thresholds {
    int cold;
    int warm;
    int hot;
} HotPyThresholds;

extern HotPyThresholds _HotPy_Thresholds;
extern HotPyStatistics _HotPy_Stats;
extern HotPyOptions _HotPy_Options;

extern void _HotPy_ShowStats(void);

typedef struct _hotpy_trace_object HotPyTraceObject;

typedef struct _hotpy_exit_object {
    PyObject_HEAD
    HotPyContext *exit_context;
    HotPyTraceObject *exit_trace;
    unsigned int execution_count;
} HotPyExitObject;

typedef struct _exit_entry {
    PyObject *value; /* Exit if var (or type(var) is eq/ne to this value */
    HotPyTraceObject *trace;
    unsigned int execution_count;
} HotPyExitEntry;

#define HOTPY_POLYMORPHIC_LIMIT 6

typedef struct _hotpy_poly_exit_object {
    PyObject_HEAD
    HotPyContext *exit_context;
    HotPyExitEntry entries[HOTPY_POLYMORPHIC_LIMIT];
} HotPyPolyExitObject;

void HotPyContext_Dump(char *buf, HotPyContext *ctx);

HotPyContext *HotPyContext_New(void);

PyObject *HotPyExitObject_New(HotPyContext *);

enum trace_status {
    TRACE_INVALID = -1,
    TRACE_NOT_READY = 0,
    TRACE_VALID
};

struct _hotpy_trace_object {
    PyObject_HEAD
    Py_ssize_t execution_count;
    PyBytesObject *trace_code;
    PyObject *trace_exits;
    PyObject *trace_constants;
    HotPyContext *trace_context;
    enum trace_status status;
    PyObject *trace_names;
    PyObject *trace_guarded_by;
    PyObject *trace_weakrefs; /* List of weak references */
    PyDictKeysObject **trace_keys;
    PyObject *poly_value;
};

void HotPyTraceObject_Init(HotPyTraceObject*, PyObject*, PyObject*, PyObject*, PyObject*);

typedef struct _optimiserobject HotPyOptimiser;

struct _optimiserobject {
    const char *opt_name;
    HotPyOptimiser *next;
    void (*push_constant)(HotPyOptimiser*, PyObject*);
    HotPyContext*(*require_type)(HotPyOptimiser*, PyTypeObject*);
    HotPyContext*(*require_lasti)(HotPyOptimiser*, int lasti);
    HotPyContext*(*require_value)(HotPyOptimiser*, PyObject*);
    HotPyContext*(*require_code)(HotPyOptimiser*, PyObject*);
    HotPyContext*(*require_boolean_or_int)(HotPyOptimiser*);
    HotPyContext*(*opcode_with_exit)(HotPyOptimiser*, int);
    HotPyContext*(*prepare_call1)(HotPyOptimiser*);
    HotPyContext*(*prepare_call2)(HotPyOptimiser*);
    HotPyContext*(*call_object)(HotPyOptimiser*);
    HotPyContext*(*call_cmethod)(HotPyOptimiser*, PyObject *, int);
    HotPyContext*(*call_cfunction)(HotPyOptimiser*, PyObject *, int);
    HotPyContext*(*call_wrapper)(HotPyOptimiser*, int, PyObject *);
    void (*clear)(HotPyOptimiser*);
    int (*start)(HotPyOptimiser*, HotPyTraceObject*, PyFrameObject*, HotPyContext*, char *reason);
    void (*finish)(HotPyOptimiser*);
    void (*fail)(HotPyOptimiser*, int, char*);
    void (*unrolling)(HotPyOptimiser*);
    void (*comment)(HotPyOptimiser*, const char*txt);
    void (*load_fast)(HotPyOptimiser*, int);
    void (*store_fast)(HotPyOptimiser*, int);
    void (*delete_fast)(HotPyOptimiser*, int);
    void (*get_globals)(HotPyOptimiser*);
    void (*load_from_globals)(HotPyOptimiser*, PyObject*);
    void (*fast_load_from_globals)(HotPyOptimiser*, PyObject*, PyObject*);
    void (*store_to_globals)(HotPyOptimiser*, PyObject*);
    void (*has_special)(HotPyOptimiser*, PyObject*);
    void (*load_register)(HotPyOptimiser*, int);
    void (*load_clear_register)(HotPyOptimiser*, int);
    void (*store_register)(HotPyOptimiser*, int);
    void (*set_lasti)(HotPyOptimiser*, int);
    void (*fast_frame)(HotPyOptimiser*, int, PyCodeObject*);
    HotPyContext*(*make_frame)(HotPyOptimiser*, PyObject *func);
    void (*make_frame_const)(HotPyOptimiser*, PyObject *func);
    void (*enter_frame)(HotPyOptimiser*, PyCodeObject*);
    void (*gen_enter)(HotPyOptimiser*, PyCodeObject*);
    void (*leave_frame)(HotPyOptimiser*);
    void (*leave_gen_frame)(HotPyOptimiser*);
    void (*binary_op)(HotPyOptimiser*, int, PyObject*);
    void (*binary_op_kv)(HotPyOptimiser*, int, PyObject*, PyObject*);
    void (*binary_op_vk)(HotPyOptimiser*, int, PyObject*, PyObject*);
    void (*tuple_concat)(HotPyOptimiser*);
    void (*pick)(HotPyOptimiser*, int);
    void (*bind_callable)(HotPyOptimiser*, PyTypeObject*);
    HotPyContext* (*load_member)(HotPyOptimiser*, PyMemberDescrObject *desc);
    HotPyContext* (*store_member)(HotPyOptimiser*, PyMemberDef*);
    void (*opcode)(HotPyOptimiser*, int);
    void (*opcode_with_arg)(HotPyOptimiser*, int, int);
    void (*setup_block)(HotPyOptimiser*, int, int, int);
    HotPyContext*(*from_object_dict_fast)(HotPyOptimiser*, int, PyDictKeysObject*, PyObject*);
    void (*set_in_object_dict_fast)(HotPyOptimiser*, int, PyDictKeysObject*, PyObject*);
    HotPyContext*(*current_context)(HotPyOptimiser*);
    void (*dead_locals)(HotPyOptimiser*);
    int instruction_count;
    HotPyContext *start_context;
};

#define MAXIMUM_TRACE_LENGTH 10000

HotPyOptimiser *HotPyTraceRecorderRegister_New(void);
HotPyOptimiser *HotPyTraceRecorder_New(void);

HotPyOptimiser *HotPySpecialiser_New(HotPyOptimiser *);

HotPyOptimiser *HotPyDOC_New(HotPyOptimiser *);

void HotPyDOC_RestoreThreadState(PyThreadState *, HotPyContext *);

HotPyOptimiser *HotPyTraceLogger_New(HotPyOptimiser *, FILE* out);

HotPyTraceObject *HotPyTraceManager_FindTrace(PyThreadState *, unsigned char *, int);

HotPyTraceObject *HotPyTraceManager_TraceForContext(PyThreadState *, HotPyContext *);

void HotPyTraceManager_InvalidateAllTraces(PyThreadState *);

void HotPyTrace_RecordingEval(PyThreadState *, HotPyTraceObject *, HotPyOptimiser *, PyObject *);

void HotPyTrace_Invalidate(PyObject *);

void HotPyTraceManager_CoolTraces(PyThreadState *);

/* Steals a reference to the trace */
HotPyReturnValue HotPyTrace_Execute(PyThreadState *, HotPyTraceObject *);

HotPyReturnValue
PyEval_RecordingEval(PyThreadState *, HotPyContext *, HotPyOptimiser *);

PyFrameObject *_PyEval_FastFrame(PyObject *, PyObject **, int);
PyFrameObject *_PyEval_MakeFrame(PyObject *, PyObject *, PyObject *);

void HotPy_RestoreThreadState(PyThreadState *, HotPyContext *context);

HotPyTraceObject *HotPyTraceObject_FromExit(PyThreadState *, HotPyExitObject *);

HotPyTraceObject *HotPyTraceObject_FromContextAndValue(PyThreadState *, HotPyContext *, PyObject *);

HotPyReturnValue HotPyTraceObject_RaiseAtExit(PyThreadState*, HotPyExitObject *);

HotPyOptimiser *HotPy_GetOptimiser(void);

HotPyReturnValue
_HotPy_RecordUnwinding(PyThreadState *, HotPyOptimiser *, HotPyContext *);

PyObject *_HotPy_PolyExit(HotPyExitObject *);

int PyType_GuardAttribute(PyTypeObject *, PyObject *, PyObject *);
void PyType_Unguard(PyTypeObject *, PyObject *);

void PyType_RemoveAllGuardsForTrace(PyTypeObject *, PyObject *);

unsigned char *_HotPy_NextInstruction(PyFrameObject *);

int HotPyDOC_IsSelfConsistent(void);

void HotPyTraceManager_Decay(void);

void HotPy_MaterialiseFrame(PyThreadState *, PyObject *, PyObject *, int);

#define HOTPY_TICK() do { \
    if (--tstate->trace_ticks <= 0) { \
        HotPyTraceManager_Decay(); \
    } \
} while (0)

#define HOTPY_MINIMUM_DECAY 2500
#define HOTPY_DEFAULT_DECAY 25000

int HotPyGuard_AddTraceToSet(PyObject *, PyObject *);
void HotPyGuard_InvalidateSet(PyObject *);

HotPyReturnValue _HotPy_TraceExcecuteCold(PyThreadState *, HotPyTraceObject *, char *);

#endif /* _HOTPY_OPTIMSER_H */
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.