├── test
├── __init__.py
└── test_net_http.py
├── pypprof
├── __init__.py
├── thread_profiler.py
├── index.html
├── builder.py
├── net_http.py
├── profile.proto
└── profile_pb2.py
├── README.md
├── .gitignore
├── setup.py
└── LICENSE
/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pypprof/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/pypprof/thread_profiler.py:
--------------------------------------------------------------------------------
1 | from collections import Counter
2 | import six
3 | import sys
4 |
5 | from pypprof import builder
6 |
7 | # Maximum stack frames to record.
8 | _MAX_STACK_DEPTH = 128
9 |
10 |
11 | def take_snapshot():
12 | samples = {extract_trace(frame): (1, 1)
13 | for frame in six.itervalues(sys._current_frames())}
14 | profile_builder = builder.Builder()
15 | profile_builder.populate_profile(samples, 'THREADS', 'count', 1, 1)
16 | return profile_builder.emit()
17 |
18 |
19 | def extract_trace(frame):
20 | """Extracts the call stack trace of the given frame.
21 |
22 | Args:
23 | frame: A Frame object representing the leaf frame of the stack.
24 |
25 | Returns:
26 | A tuple of frames. The leaf frame is at position 0. A frame is a
27 | (function name, filename, line number) tuple.
28 | """
29 | depth = 0
30 | trace = []
31 | while frame is not None and depth < _MAX_STACK_DEPTH:
32 | frame_tuple = (frame.f_code.co_name, frame.f_code.co_filename,
33 | frame.f_code.co_firstlineno, frame.f_lineno)
34 | trace.append(frame_tuple)
35 | frame = frame.f_back
36 | depth += 1
37 | return tuple(trace)
38 |
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pypprof
2 | pypprof adds HTTP-based endpoints for collecting profiles from a running Python application a la Go's [`net/http/pprof`](https://golang.org/pkg/net/http/pprof/).
3 |
4 | Under the hood, it uses [zprofile](https://github.com/timpalpant/zprofile) and [mprofile](https://github.com/timpalpant/mprofile) to collect CPU and heap profiles with minimal overhead.
5 |
6 | # Usage
7 |
8 | ## Add profiling endpoints to an application
9 |
10 | Register the profiling endpoints in your application:
11 | ```python
12 | from pypprof.net_http import start_pprof_server
13 |
14 | start_pprof_server(port=8081)
15 | ```
16 |
17 | ## Fetch profiles from your running application
18 |
19 | Fetch a 30s CPU profile, and view as a flamegraph:
20 | ```bash
21 | $ go tool pprof -http=:8088 :8081/debug/pprof/profile
22 | ```
23 |
24 | Fetch a heap profile:
25 | ```bash
26 | $ go tool pprof :8081/debug/pprof/heap
27 | ```
28 |
29 | Dump stacks from your application:
30 | ```bash
31 | $ curl localhost:8081/debug/pprof/thread?debug=1
32 | ```
33 |
34 | # Compatibility
35 |
36 | pypprof is compatible with Python >= 2.7. Memory profiling is only available by default in Python >= 3.4. To enable memory profiling in earlier Pythons, you must patch Python and manually install [mprofile](https://github.com/timpalpant/mprofile).
37 |
38 | # Contributing
39 |
40 | Pull requests and issues are welcomed!
41 |
42 | # License
43 |
44 | pypprof is released under the [GNU Lesser General Public License, Version 3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html)
45 |
--------------------------------------------------------------------------------
/pypprof/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | /debug/pprof/
4 |
10 |
11 |
12 |
13 | /debug/pprof/
14 |
15 |
16 | Types of profiles available:
17 |
18 | | Count | Profile |
19 |
20 |
21 | | 0 | cmdline |
22 |
23 |
24 |
25 | | {num_threads} | thread |
26 |
27 |
28 |
29 | | 0 | heap |
30 |
31 |
32 |
33 | | 0 | profile |
34 |
35 |
36 |
37 | | 0 | wall |
38 |
39 |
40 |
41 |
42 | full thread stack dump
43 |
44 |
45 |
46 | Profile Descriptions:
47 |
48 | cmdline:
The command line invocation of the current program
49 | thread:
Stack traces of all current threads
50 | heap:
A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.
51 | profile:
CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.
52 | wall:
Wall-clock profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool trace command to investigate the profile.
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Bazel
2 | bazel-*
3 |
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 | *$py.class
8 |
9 | # C extensions
10 | *.so
11 |
12 | # Distribution / packaging
13 | .Python
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | .hypothesis/
51 | .pytest_cache/
52 |
53 | # Translations
54 | *.mo
55 | *.pot
56 |
57 | # Django stuff:
58 | *.log
59 | local_settings.py
60 | db.sqlite3
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | target/
74 |
75 | # Jupyter Notebook
76 | .ipynb_checkpoints
77 |
78 | # pyenv
79 | .python-version
80 |
81 | # celery beat schedule file
82 | celerybeat-schedule
83 |
84 | # SageMath parsed files
85 | *.sage.py
86 |
87 | # Environments
88 | .env
89 | .venv
90 | env/
91 | venv/
92 | ENV/
93 | env.bak/
94 | venv.bak/
95 |
96 | # Spyder project settings
97 | .spyderproject
98 | .spyproject
99 |
100 | # Rope project settings
101 | .ropeproject
102 |
103 | # mkdocs documentation
104 | /site
105 |
106 | # mypy
107 | .mypy_cache/
108 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import io
2 | import os
3 | import sys
4 |
5 | from setuptools import setup
6 |
7 | README = os.path.join(os.path.abspath(os.path.dirname(__file__)), "README.md")
8 | with io.open(README, encoding="utf-8") as f:
9 | long_description = f.read()
10 |
11 | install_requires = ["protobuf", "six", "zprofile"]
12 | if sys.version_info.major >= 3:
13 | install_requires.append("mprofile")
14 |
15 | setup(
16 | name="pypprof",
17 | version="0.0.1",
18 | description="Python profiler endpoints like Go's net/http/pprof.",
19 | long_description=long_description,
20 | long_description_content_type="text/markdown",
21 | platforms=["Mac OS X", "POSIX"],
22 | classifiers=[
23 | "Development Status :: 2 - Pre-Alpha",
24 | "Intended Audience :: Developers",
25 | "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
26 | "Operating System :: POSIX",
27 | "Programming Language :: Python :: 2.7",
28 | "Programming Language :: Python :: 3.4",
29 | "Programming Language :: Python :: 3.5",
30 | "Programming Language :: Python :: 3.6",
31 | "Programming Language :: Python :: 3.7",
32 | "Programming Language :: Python :: Implementation :: CPython",
33 | "Topic :: Software Development :: Testing",
34 | "Topic :: Software Development :: Libraries :: Python Modules"
35 | ],
36 | project_urls={
37 | "Source": "https://github.com/timpalpant/pypprof",
38 | "Tracker": "https://github.com/timpalpant/pypprof/issues",
39 | },
40 | keywords="profiling performance",
41 | url="http://github.com/timpalpant/pypprof",
42 | author="Timothy Palpant",
43 | author_email="tim@palpant.us",
44 | license="LGPLv3",
45 | packages=["pypprof"],
46 | package_data={"pypprof": ["index.html"]},
47 | install_requires=install_requires,
48 | test_suite="test",
49 | )
50 |
--------------------------------------------------------------------------------
/test/test_net_http.py:
--------------------------------------------------------------------------------
1 | import gzip
2 | import io
3 | from six.moves.urllib.error import HTTPError
4 | from six.moves.urllib.request import urlopen
5 | import unittest
6 |
7 | import mprofile
8 | from pypprof.net_http import start_pprof_server
9 | from pypprof.profile_pb2 import Profile
10 |
11 |
12 | def parse_profile(buf):
13 | bufio = io.BytesIO(buf)
14 | with gzip.GzipFile(fileobj=bufio) as fd:
15 | return Profile.FromString(fd.read())
16 |
17 |
18 | class TestPprofRequestHandler(unittest.TestCase):
19 | @classmethod
20 | def setUpClass(cls):
21 | mprofile.start(sample_rate=512)
22 | cls.host = "localhost"
23 | cls.port = 8083
24 | cls.server = start_pprof_server(cls.host, cls.port)
25 |
26 | @classmethod
27 | def tearDownClass(cls):
28 | cls.server.shutdown()
29 | mprofile.stop()
30 |
31 | def _make_request(self, route):
32 | url = "http://{}:{}/debug/pprof/{}".format(
33 | self.host, self.port, route)
34 | return urlopen(url)
35 |
36 | def test_index(self):
37 | resp = self._make_request("")
38 | body = resp.read().decode("utf-8")
39 | self.assertIn("Profile Descriptions:", body)
40 |
41 | def test_cmdline(self):
42 | resp = self._make_request("cmdline")
43 | body = resp.read().decode("utf-8")
44 | self.assertTrue(len(body) > 0)
45 |
46 | def test_profile(self):
47 | resp = self._make_request("profile?seconds=1")
48 | body = resp.read()
49 | profile = parse_profile(body)
50 |
51 | def test_wall(self):
52 | resp = self._make_request("wall?seconds=1")
53 | body = resp.read()
54 | profile = parse_profile(body)
55 |
56 | def test_thread(self):
57 | resp = self._make_request("thread")
58 | body = resp.read()
59 | profile = parse_profile(body)
60 |
61 | def test_thread_debug(self):
62 | resp = self._make_request("thread?debug=2")
63 | body = resp.read().decode("utf-8")
64 | self.assertIn("pypprof/net_http.py", body)
65 | self.assertIn("test/main.py", body)
66 |
67 | def test_heap(self):
68 | resp = self._make_request("heap")
69 | body = resp.read()
70 | profile = parse_profile(body)
71 |
72 | def test_heap_gc(self):
73 | resp = self._make_request("heap?gc=1")
74 | body = resp.read()
75 | profile = parse_profile(body)
76 |
77 | def test_404(self):
78 | with self.assertRaises(HTTPError):
79 | self._make_request("noexisto")
80 |
81 |
82 | if __name__ == '__main__':
83 | unittest.main()
84 |
--------------------------------------------------------------------------------
/pypprof/builder.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Builds the profile proto from call stack traces."""
16 |
17 | import collections
18 | import gzip
19 | import io
20 | import six
21 |
22 | from pypprof import profile_pb2
23 |
24 | Func = collections.namedtuple('Func', ['name', 'filename', 'start_line'])
25 | Loc = collections.namedtuple('Loc', ['func_id', 'line_number'])
26 |
27 |
28 | class Builder(object):
29 | """Builds the profile proto from call stack traces."""
30 |
31 | def __init__(self):
32 | self._profile = profile_pb2.Profile()
33 | self._function_map = {}
34 | self._location_map = {}
35 | self._string_map = {}
36 | # string_table[0] in the profile proto must be an empty string.
37 | self._string_id('')
38 |
39 | def populate_profile(self, samples, profile_type, period_unit, period,
40 | duration_ns):
41 | """Populates call stack traces into a profile proto.
42 |
43 | Args:
44 | samples: A dict of trace => (count, measurement). A trace is a sequence of
45 | frames. The leaf frame is at trace[0]. A frame is represented as a tuple
46 | of (function name, filename, function start line, line number).
47 | profile_type: A string specifying the profile type, e.g 'CPU' or 'WALL'.
48 | See https://github.com/google/pprof/blob/master/proto/profile.proto for
49 | possible profile types.
50 | period_unit: A string specifying the measurement unit of the sampling
51 | period, e.g 'nanoseconds'.
52 | period: An integer specifying the interval between sampled occurrences.
53 | The measurement unit is specified by the period_unit argument.
54 | duration_ns: An integer specifying the profiling duration in nanoseconds.
55 | """
56 | self._profile.period_type.type = self._string_id(profile_type)
57 | self._profile.period_type.unit = self._string_id(period_unit)
58 | self._profile.period = period
59 | self._profile.duration_nanos = duration_ns
60 | type1 = self._profile.sample_type.add()
61 | type1.type = self._string_id('sample')
62 | type1.unit = self._string_id('count')
63 | type2 = self._profile.sample_type.add()
64 | type2.type = self._string_id(profile_type)
65 | type2.unit = self._string_id(period_unit)
66 |
67 | for trace, (count, value) in six.iteritems(samples):
68 | sample = self._profile.sample.add()
69 | sample.value.append(count)
70 | sample.value.append(value)
71 | for frame in trace:
72 | # TODO: try to use named tuple for frame if it doesn't over
73 | # complicate the native profiler.
74 | func_id = self._function_id(frame[0], frame[1], frame[2])
75 | location_id = self._location_id(func_id, frame[3])
76 | sample.location_id.append(location_id)
77 |
78 | def emit(self):
79 | """Returns the profile in gzip-compressed profile proto format."""
80 | profile = self._profile.SerializeToString()
81 | out = io.BytesIO()
82 | with gzip.GzipFile(fileobj=out, mode='wb') as f:
83 | f.write(profile)
84 | return out.getvalue()
85 |
86 | def _function_id(self, name, filename, start_line):
87 | """Finds the function ID in the proto, adds the function if not yet exists.
88 |
89 | Args:
90 | name: A string representing the function name.
91 | filename: A string representing the file name.
92 | start_line: The line number in filename on which this function starts.
93 |
94 | Returns:
95 | An integer representing the unique ID of the function in the profile
96 | proto.
97 | """
98 | name_id = self._string_id(name)
99 | filename_id = self._string_id(filename)
100 | func = Func(name_id, filename_id, start_line)
101 |
102 | func_id = self._function_map.get(func)
103 | if func_id is None:
104 | # Function ID in profile proto must not be zero.
105 | func_id = len(self._function_map) + 1
106 | self._function_map[func] = func_id
107 | function = self._profile.function.add()
108 | function.name = name_id
109 | function.filename = filename_id
110 | function.start_line = start_line
111 | function.id = func_id
112 | return func_id
113 |
114 | def _location_id(self, func_id, line_number):
115 | """Finds the location ID in the proto, adds the location if not yet exists.
116 |
117 | Args:
118 | func_id: An integer representing the ID of the corresponding function in
119 | the profile proto.
120 | line_number: An integer representing the line number in the source code.
121 |
122 | Returns:
123 | An integer representing the unique ID of the location in the profile
124 | proto.
125 | """
126 | loc = Loc(func_id=func_id, line_number=line_number)
127 |
128 | location_id = self._location_map.get(loc)
129 | if location_id is None:
130 | # Location ID in profile proto must not be zero.
131 | location_id = len(self._location_map) + 1
132 | self._location_map[loc] = location_id
133 | location = self._profile.location.add()
134 | location.id = location_id
135 | line = location.line.add()
136 | line.line = line_number
137 | line.function_id = func_id
138 | return location_id
139 |
140 | def _string_id(self, value):
141 | """Finds the string ID in the proto, adds the string if not yet exists."""
142 | string_id = self._string_map.get(value)
143 | if string_id is None:
144 | string_id = len(self._string_map)
145 | self._string_map[value] = string_id
146 | self._profile.string_table.append(value)
147 | return string_id
148 |
--------------------------------------------------------------------------------
/pypprof/net_http.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 |
3 | import gc
4 | import pkg_resources
5 | import sys
6 | import threading
7 | import time
8 | import traceback
9 |
10 | import six
11 | from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
12 | from six.moves.urllib.parse import parse_qs, urlparse
13 |
14 | try:
15 | import mprofile
16 | has_mprofile = True
17 | except ImportError:
18 | has_mprofile = False
19 |
20 | from zprofile.cpu_profiler import CPUProfiler
21 | from zprofile.wall_profiler import WallProfiler
22 | from pypprof.builder import Builder
23 | from pypprof import thread_profiler
24 |
25 |
26 | _wall_profiler = WallProfiler()
27 |
28 |
29 | def start_pprof_server(host='localhost', port=8080):
30 | '''Start a pprof server at the given host:port in a background thread.
31 |
32 | After calling this function, the pprof endpoints should be available
33 | at /debug/pprof/profile, etc.
34 |
35 | Returns the underlying HTTPServer. To stop the server, call shutdown().
36 | '''
37 | # WallProfiler's registers a Python signal handler, which must be done
38 | # on the main thread. So do it now before spawning the background thread.
39 | # As a result, starting the pprof server has the side effect of registering the
40 | # wall-clock profiler's SIGALRM handler, which may conflict with other uses.
41 | _wall_profiler.register_handler()
42 |
43 | server = HTTPServer((host, port), PProfRequestHandler)
44 | bg_thread = threading.Thread(target=server.serve_forever)
45 | bg_thread.daemon = True
46 | bg_thread.start()
47 | return server
48 |
49 |
50 | class PProfRequestHandler(BaseHTTPRequestHandler):
51 | '''Handle pprof endpoint requests a la Go's net/http/pprof.
52 |
53 | The following endpoints are implemented:
54 | - /debug/pprof: List the available profiles.
55 | - /debug/pprof/profile: Collect a CPU profile.
56 | - /debug/pprof/wall: Collect a wall-clock profile.
57 | - /debug/pprof/heap: Get snapshot of current heap profile.
58 | - /debug/pprof/cmdline: The running program's command line.
59 | - /debug/pprof/thread (or /debug/pprof/goroutine): Currently running threads.
60 | '''
61 | def do_GET(self):
62 | url = urlparse(self.path)
63 | route = url.path.rstrip("/")
64 | qs = parse_qs(url.query)
65 |
66 | if route == "/debug/pprof":
67 | self.index()
68 | elif route == "/debug/pprof/profile":
69 | self.profile(qs)
70 | elif route == "/debug/pprof/wall":
71 | self.wall(qs)
72 | elif route == "/debug/pprof/heap":
73 | self.heap(qs)
74 | elif route in ("/debug/pprof/thread", "/debug/pprof/goroutine"):
75 | self.thread(qs)
76 | elif route == "/debug/pprof/cmdline":
77 | self.cmdline()
78 | else:
79 | self.send_error(404)
80 |
81 | def index(self):
82 | template = pkg_resources.resource_string(__name__, "index.html").decode("utf-8")
83 | body = template.format(num_threads=threading.active_count())
84 |
85 | self.send_response(200)
86 | self.send_header("X-Content-Type-Options", "nosniff")
87 | self.send_header("Content-Type", "text/plain; charset=utf-8")
88 | self.end_headers()
89 | self.wfile.write(body.encode("utf-8"))
90 |
91 | def profile(self, query):
92 | duration_qs = query.get("seconds", [30])
93 | duration_secs = int(duration_qs[0])
94 | cpu_profiler = CPUProfiler()
95 | pprof = cpu_profiler.profile(duration_secs)
96 | self._send_profile(pprof)
97 |
98 | def wall(self, query):
99 | duration_qs = query.get("seconds", [30])
100 | duration_secs = int(duration_qs[0])
101 | pprof = _wall_profiler.profile(duration_secs)
102 | self._send_profile(pprof)
103 |
104 | def heap(self, query):
105 | if query.get("gc"):
106 | gc.collect()
107 | if not has_mprofile:
108 | return self.send_error(412, "mprofile must be installed to enable heap profiling")
109 | if not mprofile.is_tracing():
110 | return self.send_error(412, "Heap profiling is not enabled")
111 | snap = mprofile.take_snapshot()
112 | pprof = build_heap_pprof(snap)
113 | self._send_profile(pprof)
114 |
115 | def thread(self, query):
116 | if query.get("debug"):
117 | self.send_response(200)
118 | self.send_header("X-Content-Type-Options", "nosniff")
119 | self.send_header("Content-Type", "text/plain; charset=utf-8")
120 | self.end_headers()
121 | for frame in six.itervalues(sys._current_frames()):
122 | for line in traceback.format_stack(frame):
123 | self.wfile.write(line.encode("utf-8"))
124 | self.wfile.write("\n".encode("utf-8"))
125 | else:
126 | pprof = thread_profiler.take_snapshot()
127 | self._send_profile(pprof)
128 |
129 | def cmdline(self):
130 | body = "\0".join(sys.argv)
131 | self.send_response(200)
132 | self.send_header("X-Content-Type-Options", "nosniff")
133 | self.send_header("Content-Type", "text/plain; charset=utf-8")
134 | self.end_headers()
135 | self.wfile.write(body.encode("utf-8"))
136 |
137 | def _send_profile(self, pprof):
138 | self.send_response(200)
139 | self.send_header("Content-Type", "application/octet-stream")
140 | self.send_header("Content-Disposition", 'attachment; filename="profile"')
141 | self.end_headers()
142 | self.wfile.write(pprof)
143 |
144 |
145 | def build_heap_pprof(snap):
146 | profile_builder = Builder()
147 | samples = {} # trace => (count, measurement)
148 | for stat in snap.statistics('traceback'):
149 | trace = tuple((frame.name, frame.filename, frame.firstlineno, frame.lineno)
150 | for frame in stat.traceback)
151 | try:
152 | samples[trace][0] += stat.count
153 | samples[trace][1] += stat.size
154 | except KeyError:
155 | samples[trace] = (stat.count, stat.size)
156 | profile_builder.populate_profile(samples, 'HEAP', 'bytes', snap.sample_rate, 1)
157 | return profile_builder.emit()
158 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/pypprof/profile.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2016 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Profile is a common stacktrace profile format.
16 | //
17 | // Measurements represented with this format should follow the
18 | // following conventions:
19 | //
20 | // - Consumers should treat unset optional fields as if they had been
21 | // set with their default value.
22 | //
23 | // - When possible, measurements should be stored in "unsampled" form
24 | // that is most useful to humans. There should be enough
25 | // information present to determine the original sampled values.
26 | //
27 | // - On-disk, the serialized proto must be gzip-compressed.
28 | //
29 | // - The profile is represented as a set of samples, where each sample
30 | // references a sequence of locations, and where each location belongs
31 | // to a mapping.
32 | // - There is a N->1 relationship from sample.location_id entries to
33 | // locations. For every sample.location_id entry there must be a
34 | // unique Location with that id.
35 | // - There is an optional N->1 relationship from locations to
36 | // mappings. For every nonzero Location.mapping_id there must be a
37 | // unique Mapping with that id.
38 |
39 | syntax = "proto3";
40 |
41 | package perftools.profiles;
42 |
43 | option java_package = "com.google.perftools.profiles";
44 | option java_outer_classname = "ProfileProto";
45 |
46 | message Profile {
47 | // A description of the samples associated with each Sample.value.
48 | // For a cpu profile this might be:
49 | // [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]]
50 | // For a heap profile, this might be:
51 | // [["allocations","count"], ["space","bytes"]],
52 | // If one of the values represents the number of events represented
53 | // by the sample, by convention it should be at index 0 and use
54 | // sample_type.unit == "count".
55 | repeated ValueType sample_type = 1;
56 | // The set of samples recorded in this profile.
57 | repeated Sample sample = 2;
58 | // Mapping from address ranges to the image/binary/library mapped
59 | // into that address range. mapping[0] will be the main binary.
60 | repeated Mapping mapping = 3;
61 | // Useful program location
62 | repeated Location location = 4;
63 | // Functions referenced by locations
64 | repeated Function function = 5;
65 | // A common table for strings referenced by various messages.
66 | // string_table[0] must always be "".
67 | repeated string string_table = 6;
68 | // frames with Function.function_name fully matching the following
69 | // regexp will be dropped from the samples, along with their successors.
70 | int64 drop_frames = 7; // Index into string table.
71 | // frames with Function.function_name fully matching the following
72 | // regexp will be kept, even if it matches drop_functions.
73 | int64 keep_frames = 8; // Index into string table.
74 |
75 | // The following fields are informational, do not affect
76 | // interpretation of results.
77 |
78 | // Time of collection (UTC) represented as nanoseconds past the epoch.
79 | int64 time_nanos = 9;
80 | // Duration of the profile, if a duration makes sense.
81 | int64 duration_nanos = 10;
82 | // The kind of events between sampled ocurrences.
83 | // e.g [ "cpu","cycles" ] or [ "heap","bytes" ]
84 | ValueType period_type = 11;
85 | // The number of events between sampled occurrences.
86 | int64 period = 12;
87 | // Freeform text associated to the profile.
88 | repeated int64 comment = 13; // Indices into string table.
89 | // Index into the string table of the type of the preferred sample
90 | // value. If unset, clients should default to the last sample value.
91 | int64 default_sample_type = 14;
92 | }
93 |
94 | // ValueType describes the semantics and measurement units of a value.
95 | message ValueType {
96 | int64 type = 1; // Index into string table.
97 | int64 unit = 2; // Index into string table.
98 | }
99 |
100 | // Each Sample records values encountered in some program
101 | // context. The program context is typically a stack trace, perhaps
102 | // augmented with auxiliary information like the thread-id, some
103 | // indicator of a higher level request being handled etc.
104 | message Sample {
105 | // The ids recorded here correspond to a Profile.location.id.
106 | // The leaf is at location_id[0].
107 | repeated uint64 location_id = 1;
108 | // The type and unit of each value is defined by the corresponding
109 | // entry in Profile.sample_type. All samples must have the same
110 | // number of values, the same as the length of Profile.sample_type.
111 | // When aggregating multiple samples into a single sample, the
112 | // result has a list of values that is the elemntwise sum of the
113 | // lists of the originals.
114 | repeated int64 value = 2;
115 | // label includes additional context for this sample. It can include
116 | // things like a thread id, allocation size, etc
117 | repeated Label label = 3;
118 | }
119 |
120 | message Label {
121 | int64 key = 1; // Index into string table
122 |
123 | // At most one of the following must be present
124 | int64 str = 2; // Index into string table
125 | int64 num = 3;
126 |
127 | // Should only be present when num is present.
128 | // Specifies the units of num.
129 | // Use arbitrary string (for example, "requests") as a custom count unit.
130 | // If no unit is specified, consumer may apply heuristic to deduce the unit.
131 | // Consumers may also interpret units like "bytes" and "kilobytes" as memory
132 | // units and units like "seconds" and "nanoseconds" as time units,
133 | // and apply appropriate unit conversions to these.
134 | int64 num_unit = 4; // Index into string table
135 | }
136 |
137 | message Mapping {
138 | // Unique nonzero id for the mapping.
139 | uint64 id = 1;
140 | // Address at which the binary (or DLL) is loaded into memory.
141 | uint64 memory_start = 2;
142 | // The limit of the address range occupied by this mapping.
143 | uint64 memory_limit = 3;
144 | // Offset in the binary that corresponds to the first mapped address.
145 | uint64 file_offset = 4;
146 | // The object this entry is loaded from. This can be a filename on
147 | // disk for the main binary and shared libraries, or virtual
148 | // abstractions like "[vdso]".
149 | int64 filename = 5; // Index into string table
150 | // A string that uniquely identifies a particular program version
151 | // with high probability. E.g., for binaries generated by GNU tools,
152 | // it could be the contents of the .note.gnu.build-id field.
153 | int64 build_id = 6; // Index into string table
154 |
155 | // The following fields indicate the resolution of symbolic info.
156 | bool has_functions = 7;
157 | bool has_filenames = 8;
158 | bool has_line_numbers = 9;
159 | bool has_inline_frames = 10;
160 | }
161 |
162 | // Describes function and line table debug information.
163 | message Location {
164 | // Unique nonzero id for the location. A profile could use
165 | // instruction addresses or any integer sequence as ids.
166 | uint64 id = 1;
167 | // The id of the corresponding profile.Mapping for this location.
168 | // It can be unset if the mapping is unknown or not applicable for
169 | // this profile type.
170 | uint64 mapping_id = 2;
171 | // The instruction address for this location, if available. It
172 | // should be within [Mapping.memory_start...Mapping.memory_limit]
173 | // for the corresponding mapping. A non-leaf address may be in the
174 | // middle of a call instruction. It is up to display tools to find
175 | // the beginning of the instruction if necessary.
176 | uint64 address = 3;
177 | // Multiple line indicates this location has inlined functions,
178 | // where the last entry represents the caller into which the
179 | // preceding entries were inlined.
180 | //
181 | // E.g., if memcpy() is inlined into printf:
182 | // line[0].function_name == "memcpy"
183 | // line[1].function_name == "printf"
184 | repeated Line line = 4;
185 | // Provides an indication that multiple symbols map to this location's
186 | // address, for example due to identical code folding by the linker. In that
187 | // case the line information above represents one of the multiple
188 | // symbols. This field must be recomputed when the symbolization state of the
189 | // profile changes.
190 | bool is_folded = 5;
191 | }
192 |
193 | message Line {
194 | // The id of the corresponding profile.Function for this line.
195 | uint64 function_id = 1;
196 | // Line number in source code.
197 | int64 line = 2;
198 | }
199 |
200 | message Function {
201 | // Unique nonzero id for the function.
202 | uint64 id = 1;
203 | // Name of the function, in human-readable form if available.
204 | int64 name = 2; // Index into string table
205 | // Name of the function, as identified by the system.
206 | // For instance, it can be a C++ mangled name.
207 | int64 system_name = 3; // Index into string table
208 | // Source file containing the function.
209 | int64 filename = 4; // Index into string table
210 | // Line number in source file.
211 | int64 start_line = 5;
212 | }
213 |
--------------------------------------------------------------------------------
/pypprof/profile_pb2.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # Generated by the protocol buffer compiler. DO NOT EDIT!
16 | # source: profile.proto
17 | # pylint:skip-file
18 |
19 | import sys
20 | _b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode('latin1'))
21 | from google.protobuf import descriptor as _descriptor
22 | from google.protobuf import message as _message
23 | from google.protobuf import reflection as _reflection
24 | from google.protobuf import symbol_database as _symbol_database
25 | from google.protobuf import descriptor_pb2
26 | # @@protoc_insertion_point(imports)
27 |
28 | _sym_db = _symbol_database.Default()
29 |
30 | DESCRIPTOR = _descriptor.FileDescriptor(
31 | name='profile.proto',
32 | package='perftools.profiles',
33 | syntax='proto3',
34 | serialized_pb=_b(
35 | '\n\rprofile.proto\x12\x12perftools.profiles\"\xd5\x03\n\x07Profile\x12\x32\n\x0bsample_type\x18\x01 \x03(\x0b\x32\x1d.perftools.profiles.ValueType\x12*\n\x06sample\x18\x02 \x03(\x0b\x32\x1a.perftools.profiles.Sample\x12,\n\x07mapping\x18\x03 \x03(\x0b\x32\x1b.perftools.profiles.Mapping\x12.\n\x08location\x18\x04 \x03(\x0b\x32\x1c.perftools.profiles.Location\x12.\n\x08\x66unction\x18\x05 \x03(\x0b\x32\x1c.perftools.profiles.Function\x12\x14\n\x0cstring_table\x18\x06 \x03(\t\x12\x13\n\x0b\x64rop_frames\x18\x07 \x01(\x03\x12\x13\n\x0bkeep_frames\x18\x08 \x01(\x03\x12\x12\n\ntime_nanos\x18\t \x01(\x03\x12\x16\n\x0e\x64uration_nanos\x18\n \x01(\x03\x12\x32\n\x0bperiod_type\x18\x0b \x01(\x0b\x32\x1d.perftools.profiles.ValueType\x12\x0e\n\x06period\x18\x0c \x01(\x03\x12\x0f\n\x07\x63omment\x18\r \x03(\x03\x12\x1b\n\x13\x64\x65\x66\x61ult_sample_type\x18\x0e \x01(\x03\"\'\n\tValueType\x12\x0c\n\x04type\x18\x01 \x01(\x03\x12\x0c\n\x04unit\x18\x02 \x01(\x03\"V\n\x06Sample\x12\x13\n\x0blocation_id\x18\x01 \x03(\x04\x12\r\n\x05value\x18\x02 \x03(\x03\x12(\n\x05label\x18\x03 \x03(\x0b\x32\x19.perftools.profiles.Label\"@\n\x05Label\x12\x0b\n\x03key\x18\x01 \x01(\x03\x12\x0b\n\x03str\x18\x02 \x01(\x03\x12\x0b\n\x03num\x18\x03 \x01(\x03\x12\x10\n\x08num_unit\x18\x04 \x01(\x03\"\xdd\x01\n\x07Mapping\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x0cmemory_start\x18\x02 \x01(\x04\x12\x14\n\x0cmemory_limit\x18\x03 \x01(\x04\x12\x13\n\x0b\x66ile_offset\x18\x04 \x01(\x04\x12\x10\n\x08\x66ilename\x18\x05 \x01(\x03\x12\x10\n\x08\x62uild_id\x18\x06 \x01(\x03\x12\x15\n\rhas_functions\x18\x07 \x01(\x08\x12\x15\n\rhas_filenames\x18\x08 \x01(\x08\x12\x18\n\x10has_line_numbers\x18\t \x01(\x08\x12\x19\n\x11has_inline_frames\x18\n \x01(\x08\"v\n\x08Location\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x12\n\nmapping_id\x18\x02 \x01(\x04\x12\x0f\n\x07\x61\x64\x64ress\x18\x03 \x01(\x04\x12&\n\x04line\x18\x04 \x03(\x0b\x32\x18.perftools.profiles.Line\x12\x11\n\tis_folded\x18\x05 \x01(\x08\")\n\x04Line\x12\x13\n\x0b\x66unction_id\x18\x01 \x01(\x04\x12\x0c\n\x04line\x18\x02 \x01(\x03\"_\n\x08\x46unction\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0c\n\x04name\x18\x02 \x01(\x03\x12\x13\n\x0bsystem_name\x18\x03 \x01(\x03\x12\x10\n\x08\x66ilename\x18\x04 \x01(\x03\x12\x12\n\nstart_line\x18\x05 \x01(\x03\x42-\n\x1d\x63om.google.perftools.profilesB\x0cProfileProtob\x06proto3'
36 | ))
37 | _sym_db.RegisterFileDescriptor(DESCRIPTOR)
38 |
39 | _PROFILE = _descriptor.Descriptor(
40 | name='Profile',
41 | full_name='perftools.profiles.Profile',
42 | filename=None,
43 | file=DESCRIPTOR,
44 | containing_type=None,
45 | fields=[
46 | _descriptor.FieldDescriptor(
47 | name='sample_type',
48 | full_name='perftools.profiles.Profile.sample_type',
49 | index=0,
50 | number=1,
51 | type=11,
52 | cpp_type=10,
53 | label=3,
54 | has_default_value=False,
55 | default_value=[],
56 | message_type=None,
57 | enum_type=None,
58 | containing_type=None,
59 | is_extension=False,
60 | extension_scope=None,
61 | options=None),
62 | _descriptor.FieldDescriptor(
63 | name='sample',
64 | full_name='perftools.profiles.Profile.sample',
65 | index=1,
66 | number=2,
67 | type=11,
68 | cpp_type=10,
69 | label=3,
70 | has_default_value=False,
71 | default_value=[],
72 | message_type=None,
73 | enum_type=None,
74 | containing_type=None,
75 | is_extension=False,
76 | extension_scope=None,
77 | options=None),
78 | _descriptor.FieldDescriptor(
79 | name='mapping',
80 | full_name='perftools.profiles.Profile.mapping',
81 | index=2,
82 | number=3,
83 | type=11,
84 | cpp_type=10,
85 | label=3,
86 | has_default_value=False,
87 | default_value=[],
88 | message_type=None,
89 | enum_type=None,
90 | containing_type=None,
91 | is_extension=False,
92 | extension_scope=None,
93 | options=None),
94 | _descriptor.FieldDescriptor(
95 | name='location',
96 | full_name='perftools.profiles.Profile.location',
97 | index=3,
98 | number=4,
99 | type=11,
100 | cpp_type=10,
101 | label=3,
102 | has_default_value=False,
103 | default_value=[],
104 | message_type=None,
105 | enum_type=None,
106 | containing_type=None,
107 | is_extension=False,
108 | extension_scope=None,
109 | options=None),
110 | _descriptor.FieldDescriptor(
111 | name='function',
112 | full_name='perftools.profiles.Profile.function',
113 | index=4,
114 | number=5,
115 | type=11,
116 | cpp_type=10,
117 | label=3,
118 | has_default_value=False,
119 | default_value=[],
120 | message_type=None,
121 | enum_type=None,
122 | containing_type=None,
123 | is_extension=False,
124 | extension_scope=None,
125 | options=None),
126 | _descriptor.FieldDescriptor(
127 | name='string_table',
128 | full_name='perftools.profiles.Profile.string_table',
129 | index=5,
130 | number=6,
131 | type=9,
132 | cpp_type=9,
133 | label=3,
134 | has_default_value=False,
135 | default_value=[],
136 | message_type=None,
137 | enum_type=None,
138 | containing_type=None,
139 | is_extension=False,
140 | extension_scope=None,
141 | options=None),
142 | _descriptor.FieldDescriptor(
143 | name='drop_frames',
144 | full_name='perftools.profiles.Profile.drop_frames',
145 | index=6,
146 | number=7,
147 | type=3,
148 | cpp_type=2,
149 | label=1,
150 | has_default_value=False,
151 | default_value=0,
152 | message_type=None,
153 | enum_type=None,
154 | containing_type=None,
155 | is_extension=False,
156 | extension_scope=None,
157 | options=None),
158 | _descriptor.FieldDescriptor(
159 | name='keep_frames',
160 | full_name='perftools.profiles.Profile.keep_frames',
161 | index=7,
162 | number=8,
163 | type=3,
164 | cpp_type=2,
165 | label=1,
166 | has_default_value=False,
167 | default_value=0,
168 | message_type=None,
169 | enum_type=None,
170 | containing_type=None,
171 | is_extension=False,
172 | extension_scope=None,
173 | options=None),
174 | _descriptor.FieldDescriptor(
175 | name='time_nanos',
176 | full_name='perftools.profiles.Profile.time_nanos',
177 | index=8,
178 | number=9,
179 | type=3,
180 | cpp_type=2,
181 | label=1,
182 | has_default_value=False,
183 | default_value=0,
184 | message_type=None,
185 | enum_type=None,
186 | containing_type=None,
187 | is_extension=False,
188 | extension_scope=None,
189 | options=None),
190 | _descriptor.FieldDescriptor(
191 | name='duration_nanos',
192 | full_name='perftools.profiles.Profile.duration_nanos',
193 | index=9,
194 | number=10,
195 | type=3,
196 | cpp_type=2,
197 | label=1,
198 | has_default_value=False,
199 | default_value=0,
200 | message_type=None,
201 | enum_type=None,
202 | containing_type=None,
203 | is_extension=False,
204 | extension_scope=None,
205 | options=None),
206 | _descriptor.FieldDescriptor(
207 | name='period_type',
208 | full_name='perftools.profiles.Profile.period_type',
209 | index=10,
210 | number=11,
211 | type=11,
212 | cpp_type=10,
213 | label=1,
214 | has_default_value=False,
215 | default_value=None,
216 | message_type=None,
217 | enum_type=None,
218 | containing_type=None,
219 | is_extension=False,
220 | extension_scope=None,
221 | options=None),
222 | _descriptor.FieldDescriptor(
223 | name='period',
224 | full_name='perftools.profiles.Profile.period',
225 | index=11,
226 | number=12,
227 | type=3,
228 | cpp_type=2,
229 | label=1,
230 | has_default_value=False,
231 | default_value=0,
232 | message_type=None,
233 | enum_type=None,
234 | containing_type=None,
235 | is_extension=False,
236 | extension_scope=None,
237 | options=None),
238 | _descriptor.FieldDescriptor(
239 | name='comment',
240 | full_name='perftools.profiles.Profile.comment',
241 | index=12,
242 | number=13,
243 | type=3,
244 | cpp_type=2,
245 | label=3,
246 | has_default_value=False,
247 | default_value=[],
248 | message_type=None,
249 | enum_type=None,
250 | containing_type=None,
251 | is_extension=False,
252 | extension_scope=None,
253 | options=None),
254 | _descriptor.FieldDescriptor(
255 | name='default_sample_type',
256 | full_name='perftools.profiles.Profile.default_sample_type',
257 | index=13,
258 | number=14,
259 | type=3,
260 | cpp_type=2,
261 | label=1,
262 | has_default_value=False,
263 | default_value=0,
264 | message_type=None,
265 | enum_type=None,
266 | containing_type=None,
267 | is_extension=False,
268 | extension_scope=None,
269 | options=None),
270 | ],
271 | extensions=[],
272 | nested_types=[],
273 | enum_types=[],
274 | options=None,
275 | is_extendable=False,
276 | syntax='proto3',
277 | extension_ranges=[],
278 | oneofs=[],
279 | serialized_start=38,
280 | serialized_end=507,
281 | )
282 |
283 | _VALUETYPE = _descriptor.Descriptor(
284 | name='ValueType',
285 | full_name='perftools.profiles.ValueType',
286 | filename=None,
287 | file=DESCRIPTOR,
288 | containing_type=None,
289 | fields=[
290 | _descriptor.FieldDescriptor(
291 | name='type',
292 | full_name='perftools.profiles.ValueType.type',
293 | index=0,
294 | number=1,
295 | type=3,
296 | cpp_type=2,
297 | label=1,
298 | has_default_value=False,
299 | default_value=0,
300 | message_type=None,
301 | enum_type=None,
302 | containing_type=None,
303 | is_extension=False,
304 | extension_scope=None,
305 | options=None),
306 | _descriptor.FieldDescriptor(
307 | name='unit',
308 | full_name='perftools.profiles.ValueType.unit',
309 | index=1,
310 | number=2,
311 | type=3,
312 | cpp_type=2,
313 | label=1,
314 | has_default_value=False,
315 | default_value=0,
316 | message_type=None,
317 | enum_type=None,
318 | containing_type=None,
319 | is_extension=False,
320 | extension_scope=None,
321 | options=None),
322 | ],
323 | extensions=[],
324 | nested_types=[],
325 | enum_types=[],
326 | options=None,
327 | is_extendable=False,
328 | syntax='proto3',
329 | extension_ranges=[],
330 | oneofs=[],
331 | serialized_start=509,
332 | serialized_end=548,
333 | )
334 |
335 | _SAMPLE = _descriptor.Descriptor(
336 | name='Sample',
337 | full_name='perftools.profiles.Sample',
338 | filename=None,
339 | file=DESCRIPTOR,
340 | containing_type=None,
341 | fields=[
342 | _descriptor.FieldDescriptor(
343 | name='location_id',
344 | full_name='perftools.profiles.Sample.location_id',
345 | index=0,
346 | number=1,
347 | type=4,
348 | cpp_type=4,
349 | label=3,
350 | has_default_value=False,
351 | default_value=[],
352 | message_type=None,
353 | enum_type=None,
354 | containing_type=None,
355 | is_extension=False,
356 | extension_scope=None,
357 | options=None),
358 | _descriptor.FieldDescriptor(
359 | name='value',
360 | full_name='perftools.profiles.Sample.value',
361 | index=1,
362 | number=2,
363 | type=3,
364 | cpp_type=2,
365 | label=3,
366 | has_default_value=False,
367 | default_value=[],
368 | message_type=None,
369 | enum_type=None,
370 | containing_type=None,
371 | is_extension=False,
372 | extension_scope=None,
373 | options=None),
374 | _descriptor.FieldDescriptor(
375 | name='label',
376 | full_name='perftools.profiles.Sample.label',
377 | index=2,
378 | number=3,
379 | type=11,
380 | cpp_type=10,
381 | label=3,
382 | has_default_value=False,
383 | default_value=[],
384 | message_type=None,
385 | enum_type=None,
386 | containing_type=None,
387 | is_extension=False,
388 | extension_scope=None,
389 | options=None),
390 | ],
391 | extensions=[],
392 | nested_types=[],
393 | enum_types=[],
394 | options=None,
395 | is_extendable=False,
396 | syntax='proto3',
397 | extension_ranges=[],
398 | oneofs=[],
399 | serialized_start=550,
400 | serialized_end=636,
401 | )
402 |
403 | _LABEL = _descriptor.Descriptor(
404 | name='Label',
405 | full_name='perftools.profiles.Label',
406 | filename=None,
407 | file=DESCRIPTOR,
408 | containing_type=None,
409 | fields=[
410 | _descriptor.FieldDescriptor(
411 | name='key',
412 | full_name='perftools.profiles.Label.key',
413 | index=0,
414 | number=1,
415 | type=3,
416 | cpp_type=2,
417 | label=1,
418 | has_default_value=False,
419 | default_value=0,
420 | message_type=None,
421 | enum_type=None,
422 | containing_type=None,
423 | is_extension=False,
424 | extension_scope=None,
425 | options=None),
426 | _descriptor.FieldDescriptor(
427 | name='str',
428 | full_name='perftools.profiles.Label.str',
429 | index=1,
430 | number=2,
431 | type=3,
432 | cpp_type=2,
433 | label=1,
434 | has_default_value=False,
435 | default_value=0,
436 | message_type=None,
437 | enum_type=None,
438 | containing_type=None,
439 | is_extension=False,
440 | extension_scope=None,
441 | options=None),
442 | _descriptor.FieldDescriptor(
443 | name='num',
444 | full_name='perftools.profiles.Label.num',
445 | index=2,
446 | number=3,
447 | type=3,
448 | cpp_type=2,
449 | label=1,
450 | has_default_value=False,
451 | default_value=0,
452 | message_type=None,
453 | enum_type=None,
454 | containing_type=None,
455 | is_extension=False,
456 | extension_scope=None,
457 | options=None),
458 | _descriptor.FieldDescriptor(
459 | name='num_unit',
460 | full_name='perftools.profiles.Label.num_unit',
461 | index=3,
462 | number=4,
463 | type=3,
464 | cpp_type=2,
465 | label=1,
466 | has_default_value=False,
467 | default_value=0,
468 | message_type=None,
469 | enum_type=None,
470 | containing_type=None,
471 | is_extension=False,
472 | extension_scope=None,
473 | options=None),
474 | ],
475 | extensions=[],
476 | nested_types=[],
477 | enum_types=[],
478 | options=None,
479 | is_extendable=False,
480 | syntax='proto3',
481 | extension_ranges=[],
482 | oneofs=[],
483 | serialized_start=638,
484 | serialized_end=702,
485 | )
486 |
487 | _MAPPING = _descriptor.Descriptor(
488 | name='Mapping',
489 | full_name='perftools.profiles.Mapping',
490 | filename=None,
491 | file=DESCRIPTOR,
492 | containing_type=None,
493 | fields=[
494 | _descriptor.FieldDescriptor(
495 | name='id',
496 | full_name='perftools.profiles.Mapping.id',
497 | index=0,
498 | number=1,
499 | type=4,
500 | cpp_type=4,
501 | label=1,
502 | has_default_value=False,
503 | default_value=0,
504 | message_type=None,
505 | enum_type=None,
506 | containing_type=None,
507 | is_extension=False,
508 | extension_scope=None,
509 | options=None),
510 | _descriptor.FieldDescriptor(
511 | name='memory_start',
512 | full_name='perftools.profiles.Mapping.memory_start',
513 | index=1,
514 | number=2,
515 | type=4,
516 | cpp_type=4,
517 | label=1,
518 | has_default_value=False,
519 | default_value=0,
520 | message_type=None,
521 | enum_type=None,
522 | containing_type=None,
523 | is_extension=False,
524 | extension_scope=None,
525 | options=None),
526 | _descriptor.FieldDescriptor(
527 | name='memory_limit',
528 | full_name='perftools.profiles.Mapping.memory_limit',
529 | index=2,
530 | number=3,
531 | type=4,
532 | cpp_type=4,
533 | label=1,
534 | has_default_value=False,
535 | default_value=0,
536 | message_type=None,
537 | enum_type=None,
538 | containing_type=None,
539 | is_extension=False,
540 | extension_scope=None,
541 | options=None),
542 | _descriptor.FieldDescriptor(
543 | name='file_offset',
544 | full_name='perftools.profiles.Mapping.file_offset',
545 | index=3,
546 | number=4,
547 | type=4,
548 | cpp_type=4,
549 | label=1,
550 | has_default_value=False,
551 | default_value=0,
552 | message_type=None,
553 | enum_type=None,
554 | containing_type=None,
555 | is_extension=False,
556 | extension_scope=None,
557 | options=None),
558 | _descriptor.FieldDescriptor(
559 | name='filename',
560 | full_name='perftools.profiles.Mapping.filename',
561 | index=4,
562 | number=5,
563 | type=3,
564 | cpp_type=2,
565 | label=1,
566 | has_default_value=False,
567 | default_value=0,
568 | message_type=None,
569 | enum_type=None,
570 | containing_type=None,
571 | is_extension=False,
572 | extension_scope=None,
573 | options=None),
574 | _descriptor.FieldDescriptor(
575 | name='build_id',
576 | full_name='perftools.profiles.Mapping.build_id',
577 | index=5,
578 | number=6,
579 | type=3,
580 | cpp_type=2,
581 | label=1,
582 | has_default_value=False,
583 | default_value=0,
584 | message_type=None,
585 | enum_type=None,
586 | containing_type=None,
587 | is_extension=False,
588 | extension_scope=None,
589 | options=None),
590 | _descriptor.FieldDescriptor(
591 | name='has_functions',
592 | full_name='perftools.profiles.Mapping.has_functions',
593 | index=6,
594 | number=7,
595 | type=8,
596 | cpp_type=7,
597 | label=1,
598 | has_default_value=False,
599 | default_value=False,
600 | message_type=None,
601 | enum_type=None,
602 | containing_type=None,
603 | is_extension=False,
604 | extension_scope=None,
605 | options=None),
606 | _descriptor.FieldDescriptor(
607 | name='has_filenames',
608 | full_name='perftools.profiles.Mapping.has_filenames',
609 | index=7,
610 | number=8,
611 | type=8,
612 | cpp_type=7,
613 | label=1,
614 | has_default_value=False,
615 | default_value=False,
616 | message_type=None,
617 | enum_type=None,
618 | containing_type=None,
619 | is_extension=False,
620 | extension_scope=None,
621 | options=None),
622 | _descriptor.FieldDescriptor(
623 | name='has_line_numbers',
624 | full_name='perftools.profiles.Mapping.has_line_numbers',
625 | index=8,
626 | number=9,
627 | type=8,
628 | cpp_type=7,
629 | label=1,
630 | has_default_value=False,
631 | default_value=False,
632 | message_type=None,
633 | enum_type=None,
634 | containing_type=None,
635 | is_extension=False,
636 | extension_scope=None,
637 | options=None),
638 | _descriptor.FieldDescriptor(
639 | name='has_inline_frames',
640 | full_name='perftools.profiles.Mapping.has_inline_frames',
641 | index=9,
642 | number=10,
643 | type=8,
644 | cpp_type=7,
645 | label=1,
646 | has_default_value=False,
647 | default_value=False,
648 | message_type=None,
649 | enum_type=None,
650 | containing_type=None,
651 | is_extension=False,
652 | extension_scope=None,
653 | options=None),
654 | ],
655 | extensions=[],
656 | nested_types=[],
657 | enum_types=[],
658 | options=None,
659 | is_extendable=False,
660 | syntax='proto3',
661 | extension_ranges=[],
662 | oneofs=[],
663 | serialized_start=705,
664 | serialized_end=926,
665 | )
666 |
667 | _LOCATION = _descriptor.Descriptor(
668 | name='Location',
669 | full_name='perftools.profiles.Location',
670 | filename=None,
671 | file=DESCRIPTOR,
672 | containing_type=None,
673 | fields=[
674 | _descriptor.FieldDescriptor(
675 | name='id',
676 | full_name='perftools.profiles.Location.id',
677 | index=0,
678 | number=1,
679 | type=4,
680 | cpp_type=4,
681 | label=1,
682 | has_default_value=False,
683 | default_value=0,
684 | message_type=None,
685 | enum_type=None,
686 | containing_type=None,
687 | is_extension=False,
688 | extension_scope=None,
689 | options=None),
690 | _descriptor.FieldDescriptor(
691 | name='mapping_id',
692 | full_name='perftools.profiles.Location.mapping_id',
693 | index=1,
694 | number=2,
695 | type=4,
696 | cpp_type=4,
697 | label=1,
698 | has_default_value=False,
699 | default_value=0,
700 | message_type=None,
701 | enum_type=None,
702 | containing_type=None,
703 | is_extension=False,
704 | extension_scope=None,
705 | options=None),
706 | _descriptor.FieldDescriptor(
707 | name='address',
708 | full_name='perftools.profiles.Location.address',
709 | index=2,
710 | number=3,
711 | type=4,
712 | cpp_type=4,
713 | label=1,
714 | has_default_value=False,
715 | default_value=0,
716 | message_type=None,
717 | enum_type=None,
718 | containing_type=None,
719 | is_extension=False,
720 | extension_scope=None,
721 | options=None),
722 | _descriptor.FieldDescriptor(
723 | name='line',
724 | full_name='perftools.profiles.Location.line',
725 | index=3,
726 | number=4,
727 | type=11,
728 | cpp_type=10,
729 | label=3,
730 | has_default_value=False,
731 | default_value=[],
732 | message_type=None,
733 | enum_type=None,
734 | containing_type=None,
735 | is_extension=False,
736 | extension_scope=None,
737 | options=None),
738 | _descriptor.FieldDescriptor(
739 | name='is_folded',
740 | full_name='perftools.profiles.Location.is_folded',
741 | index=4,
742 | number=5,
743 | type=8,
744 | cpp_type=7,
745 | label=1,
746 | has_default_value=False,
747 | default_value=False,
748 | message_type=None,
749 | enum_type=None,
750 | containing_type=None,
751 | is_extension=False,
752 | extension_scope=None,
753 | options=None),
754 | ],
755 | extensions=[],
756 | nested_types=[],
757 | enum_types=[],
758 | options=None,
759 | is_extendable=False,
760 | syntax='proto3',
761 | extension_ranges=[],
762 | oneofs=[],
763 | serialized_start=928,
764 | serialized_end=1046,
765 | )
766 |
767 | _LINE = _descriptor.Descriptor(
768 | name='Line',
769 | full_name='perftools.profiles.Line',
770 | filename=None,
771 | file=DESCRIPTOR,
772 | containing_type=None,
773 | fields=[
774 | _descriptor.FieldDescriptor(
775 | name='function_id',
776 | full_name='perftools.profiles.Line.function_id',
777 | index=0,
778 | number=1,
779 | type=4,
780 | cpp_type=4,
781 | label=1,
782 | has_default_value=False,
783 | default_value=0,
784 | message_type=None,
785 | enum_type=None,
786 | containing_type=None,
787 | is_extension=False,
788 | extension_scope=None,
789 | options=None),
790 | _descriptor.FieldDescriptor(
791 | name='line',
792 | full_name='perftools.profiles.Line.line',
793 | index=1,
794 | number=2,
795 | type=3,
796 | cpp_type=2,
797 | label=1,
798 | has_default_value=False,
799 | default_value=0,
800 | message_type=None,
801 | enum_type=None,
802 | containing_type=None,
803 | is_extension=False,
804 | extension_scope=None,
805 | options=None),
806 | ],
807 | extensions=[],
808 | nested_types=[],
809 | enum_types=[],
810 | options=None,
811 | is_extendable=False,
812 | syntax='proto3',
813 | extension_ranges=[],
814 | oneofs=[],
815 | serialized_start=1048,
816 | serialized_end=1089,
817 | )
818 |
819 | _FUNCTION = _descriptor.Descriptor(
820 | name='Function',
821 | full_name='perftools.profiles.Function',
822 | filename=None,
823 | file=DESCRIPTOR,
824 | containing_type=None,
825 | fields=[
826 | _descriptor.FieldDescriptor(
827 | name='id',
828 | full_name='perftools.profiles.Function.id',
829 | index=0,
830 | number=1,
831 | type=4,
832 | cpp_type=4,
833 | label=1,
834 | has_default_value=False,
835 | default_value=0,
836 | message_type=None,
837 | enum_type=None,
838 | containing_type=None,
839 | is_extension=False,
840 | extension_scope=None,
841 | options=None),
842 | _descriptor.FieldDescriptor(
843 | name='name',
844 | full_name='perftools.profiles.Function.name',
845 | index=1,
846 | number=2,
847 | type=3,
848 | cpp_type=2,
849 | label=1,
850 | has_default_value=False,
851 | default_value=0,
852 | message_type=None,
853 | enum_type=None,
854 | containing_type=None,
855 | is_extension=False,
856 | extension_scope=None,
857 | options=None),
858 | _descriptor.FieldDescriptor(
859 | name='system_name',
860 | full_name='perftools.profiles.Function.system_name',
861 | index=2,
862 | number=3,
863 | type=3,
864 | cpp_type=2,
865 | label=1,
866 | has_default_value=False,
867 | default_value=0,
868 | message_type=None,
869 | enum_type=None,
870 | containing_type=None,
871 | is_extension=False,
872 | extension_scope=None,
873 | options=None),
874 | _descriptor.FieldDescriptor(
875 | name='filename',
876 | full_name='perftools.profiles.Function.filename',
877 | index=3,
878 | number=4,
879 | type=3,
880 | cpp_type=2,
881 | label=1,
882 | has_default_value=False,
883 | default_value=0,
884 | message_type=None,
885 | enum_type=None,
886 | containing_type=None,
887 | is_extension=False,
888 | extension_scope=None,
889 | options=None),
890 | _descriptor.FieldDescriptor(
891 | name='start_line',
892 | full_name='perftools.profiles.Function.start_line',
893 | index=4,
894 | number=5,
895 | type=3,
896 | cpp_type=2,
897 | label=1,
898 | has_default_value=False,
899 | default_value=0,
900 | message_type=None,
901 | enum_type=None,
902 | containing_type=None,
903 | is_extension=False,
904 | extension_scope=None,
905 | options=None),
906 | ],
907 | extensions=[],
908 | nested_types=[],
909 | enum_types=[],
910 | options=None,
911 | is_extendable=False,
912 | syntax='proto3',
913 | extension_ranges=[],
914 | oneofs=[],
915 | serialized_start=1091,
916 | serialized_end=1186,
917 | )
918 |
919 | _PROFILE.fields_by_name['sample_type'].message_type = _VALUETYPE
920 | _PROFILE.fields_by_name['sample'].message_type = _SAMPLE
921 | _PROFILE.fields_by_name['mapping'].message_type = _MAPPING
922 | _PROFILE.fields_by_name['location'].message_type = _LOCATION
923 | _PROFILE.fields_by_name['function'].message_type = _FUNCTION
924 | _PROFILE.fields_by_name['period_type'].message_type = _VALUETYPE
925 | _SAMPLE.fields_by_name['label'].message_type = _LABEL
926 | _LOCATION.fields_by_name['line'].message_type = _LINE
927 | DESCRIPTOR.message_types_by_name['Profile'] = _PROFILE
928 | DESCRIPTOR.message_types_by_name['ValueType'] = _VALUETYPE
929 | DESCRIPTOR.message_types_by_name['Sample'] = _SAMPLE
930 | DESCRIPTOR.message_types_by_name['Label'] = _LABEL
931 | DESCRIPTOR.message_types_by_name['Mapping'] = _MAPPING
932 | DESCRIPTOR.message_types_by_name['Location'] = _LOCATION
933 | DESCRIPTOR.message_types_by_name['Line'] = _LINE
934 | DESCRIPTOR.message_types_by_name['Function'] = _FUNCTION
935 |
936 | Profile = _reflection.GeneratedProtocolMessageType(
937 | 'Profile',
938 | (_message.Message,),
939 | dict(
940 | DESCRIPTOR=_PROFILE,
941 | __module__='profile_pb2'
942 | # @@protoc_insertion_point(class_scope:perftools.profiles.Profile)
943 | ))
944 | _sym_db.RegisterMessage(Profile)
945 |
946 | ValueType = _reflection.GeneratedProtocolMessageType(
947 | 'ValueType',
948 | (_message.Message,),
949 | dict(
950 | DESCRIPTOR=_VALUETYPE,
951 | __module__='profile_pb2'
952 | # @@protoc_insertion_point(class_scope:perftools.profiles.ValueType)
953 | ))
954 | _sym_db.RegisterMessage(ValueType)
955 |
956 | Sample = _reflection.GeneratedProtocolMessageType(
957 | 'Sample',
958 | (_message.Message,),
959 | dict(
960 | DESCRIPTOR=_SAMPLE,
961 | __module__='profile_pb2'
962 | # @@protoc_insertion_point(class_scope:perftools.profiles.Sample)
963 | ))
964 | _sym_db.RegisterMessage(Sample)
965 |
966 | Label = _reflection.GeneratedProtocolMessageType(
967 | 'Label',
968 | (_message.Message,),
969 | dict(
970 | DESCRIPTOR=_LABEL,
971 | __module__='profile_pb2'
972 | # @@protoc_insertion_point(class_scope:perftools.profiles.Label)
973 | ))
974 | _sym_db.RegisterMessage(Label)
975 |
976 | Mapping = _reflection.GeneratedProtocolMessageType(
977 | 'Mapping',
978 | (_message.Message,),
979 | dict(
980 | DESCRIPTOR=_MAPPING,
981 | __module__='profile_pb2'
982 | # @@protoc_insertion_point(class_scope:perftools.profiles.Mapping)
983 | ))
984 | _sym_db.RegisterMessage(Mapping)
985 |
986 | Location = _reflection.GeneratedProtocolMessageType(
987 | 'Location',
988 | (_message.Message,),
989 | dict(
990 | DESCRIPTOR=_LOCATION,
991 | __module__='profile_pb2'
992 | # @@protoc_insertion_point(class_scope:perftools.profiles.Location)
993 | ))
994 | _sym_db.RegisterMessage(Location)
995 |
996 | Line = _reflection.GeneratedProtocolMessageType(
997 | 'Line',
998 | (_message.Message,),
999 | dict(
1000 | DESCRIPTOR=_LINE,
1001 | __module__='profile_pb2'
1002 | # @@protoc_insertion_point(class_scope:perftools.profiles.Line)
1003 | ))
1004 | _sym_db.RegisterMessage(Line)
1005 |
1006 | Function = _reflection.GeneratedProtocolMessageType(
1007 | 'Function',
1008 | (_message.Message,),
1009 | dict(
1010 | DESCRIPTOR=_FUNCTION,
1011 | __module__='profile_pb2'
1012 | # @@protoc_insertion_point(class_scope:perftools.profiles.Function)
1013 | ))
1014 | _sym_db.RegisterMessage(Function)
1015 |
1016 | DESCRIPTOR.has_options = True
1017 | DESCRIPTOR._options = _descriptor._ParseOptions(
1018 | descriptor_pb2.FileOptions(),
1019 | _b('\n\035com.google.perftools.profilesB\014ProfileProto'))
1020 | # @@protoc_insertion_point(module_scope)
1021 |
--------------------------------------------------------------------------------