sdpython / cpyquickhelper

@@ -7,6 +7,12 @@
Loading
7 7
import numpy
8 8
import pandas
9 9
from ._event_profiler import CEventProfiler  # pylint: disable=E0611
10 +
from ._event_profiler_c import (  # pylint: disable=E0611
11 +
    _profiling_start, _profiling_stop,
12 +
    _profiling_n_columns, _profiling_log_event,
13 +
    _profiling_delete, _profiling_get_saved_maps,
14 +
    _profiling_dump_and_clear,
15 +
    _profiling_register_pyinstance)
10 16
11 17
12 18
class EventProfiler:
@@ -18,7 +24,7 @@
Loading
18 24
19 25
    :param size: size of the buffer to store events
20 26
    :param impl: different implementation of the same
21 -
        function (`'python'`, `'pybind11'`)
27 +
        function (`'python'`, `'pybind11'`, `'c'`)
22 28
23 29
    The profiler stores every event about function calls and returns,
24 30
    and memory allocation. It does not give the time spent in every function
@@ -73,14 +79,20 @@
Loading
73 79
        self._prof = None
74 80
        self._frames = {-1: inspect.currentframe()}
75 81
        self._args = {-1: None, 0: None, id(None): None}
76 -
        self._buffer = CEventProfiler(size)
82 +
        if impl != 'c':
83 +
            self._buffer = CEventProfiler(size)
84 +
        else:
85 +
            self._buffer = None
86 +
            self._size = size
77 87
        self._events = []
78 88
        self._impl = impl
79 89
        self._copy_cache = False
80 -
        self._cache_copy = numpy.empty((size, self._buffer.n_columns()),
81 -
                                       dtype=numpy.int64)
90 +
        if self._buffer is None:
91 +
            nc = _profiling_n_columns()
92 +
        else:
93 +
            nc = self.n_columns
94 +
        self._cache_copy = numpy.empty((size, nc), dtype=numpy.int64)
82 95
        if impl == 'pybind11':
83 -
            # self._buffer.register_empty_cache(self._empty_cache)
84 96
            self._buffer.register_pyinstance(self)
85 97
86 98
    @property
@@ -90,7 +102,9 @@
Loading
90 102
        in memory. This corresponds to the number of columns returned
91 103
        by @see meth retrieve_raw_results.
92 104
        """
93 -
        return self._buffer.n_columns()
105 +
        if self._buffer is not None:
106 +
            return CEventProfiler.n_columns()
107 +
        return _profiling_n_columns()
94 108
95 109
    def start(self):
96 110
        """
@@ -102,9 +116,14 @@
Loading
102 116
        self._frames[0] = inspect.currentframe()
103 117
        self._started = True
104 118
        self._copy_cache = False
105 -
        self._setup_profiler()
106 -
        self._buffer.log_event(-1, -1, 100, 0, 0)
107 -
        self._buffer.start()
119 +
        if self._buffer is not None:
120 +
            self._setup_profiler()
121 +
            self._buffer.log_event(-1, -1, 100, 0, 0)
122 +
            self._buffer.start()
123 +
        else:
124 +
            _profiling_start(int(self._size), 0)
125 +
            self._setup_profiler()
126 +
            _profiling_register_pyinstance(self)
108 127
109 128
    def stop(self):
110 129
        """
@@ -114,13 +133,21 @@
Loading
114 133
            raise RuntimeError(
115 134
                "The profiler was not started. It must be done first.")
116 135
        self._restore_profiler()
117 -
        self._buffer.stop()
118 -
        self._buffer.log_event(-1, -1, 101, 0, 0)
119 -
        if self._impl == 'pybind11':
120 -
            map_frame, map_arg = self._buffer.get_saved_maps()
136 +
        if self._buffer is not None:
137 +
            self._buffer.stop()
138 +
            self._buffer.log_event(-1, -1, 101, 0, 0)
139 +
            if self._impl == 'pybind11':
140 +
                map_frame, map_arg = self._buffer.get_saved_maps()
141 +
                self._frames.update(map_frame)
142 +
                self._args.update(map_arg)
143 +
            self._buffer.delete()
144 +
        else:
145 +
            map_frame, map_arg = _profiling_get_saved_maps()
146 +
            self._empty_cache()
147 +
            _profiling_delete()
148 +
            _profiling_stop()
121 149
            self._frames.update(map_frame)
122 150
            self._args.update(map_arg)
123 -
        self._buffer.delete()
124 151
        self._started = False
125 152
126 153
    def _setup_profiler(self):
@@ -132,6 +159,8 @@
Loading
132 159
            sys.setprofile(self.log_event)
133 160
        elif self._impl == 'pybind11':
134 161
            sys.setprofile(self._buffer.c_log_event)
162 +
        elif self._impl == 'c':
163 +
            sys.setprofile(_profiling_log_event)
135 164
        else:
136 165
            raise ValueError(
137 166
                "Unexpected value for impl=%r." % self._impl)
@@ -176,9 +205,16 @@
Loading
176 205
            raise RuntimeError(
177 206
                "Profiling cache being copied. Increase the size of the cache.")
178 207
        self._copy_cache = True
179 -
        size = self._buffer.dump_and_clear(self._cache_copy, True)
208 +
        if self._buffer is None:
209 +
            ptr = self._cache_copy.__array_interface__[  # pylint: disable=E1101
210 +
                'data'][0]
211 +
            # self._cache_copy.__array_struct__
212 +
            size = _profiling_dump_and_clear(
213 +
                ptr, self._cache_copy.size, 1)
214 +
        else:
215 +
            size = self._buffer.dump_and_clear(self._cache_copy, True)
180 216
        # We hope here this function will not be called by another
181 -
        # thread. That would another thread was able to fill
217 +
        # thread which could be able to fill
182 218
        # the cache while it is being copied.
183 219
        self._events.append(self._cache_copy[:size].copy())
184 220
        self._copy_cache = False
@@ -192,7 +228,7 @@
Loading
192 228
            stores it in a numpy array before
193 229
        :return: numpy array
194 230
        """
195 -
        if empty_cache:
231 +
        if empty_cache and self._buffer is not None:
196 232
            self._empty_cache()
197 233
        res = numpy.vstack(self._events)
198 234
        # Filling information about the size of freed buffer.
Files Coverage
cpyquickhelper 96.30%
Project Totals (13 files) 96.30%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading