From 3f205ec3e907b6823b6dc44c9cfbd25922cdd9e5 Mon Sep 17 00:00:00 2001 From: Jamie Wong Date: Wed, 26 Sep 2018 11:33:34 -0700 Subject: [PATCH] Add go tool pprof import support (#165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds support for importing from Google's pprof format, which is a gzipped, protobuf encoded file format (that's incredibly well documented!) The [pprof http library](https://golang.org/pkg/net/http/pprof/) also offers an output of the trace file format, which continues to not be supported in speedscope to date (See #77). This will allow importing of profiles generated by the standard library go profiler for analysis of profiles containing heap allocation information, CPU profile information, and a few other things like coroutine creation information. In order to add support for that a number of dependent bits of functionality were added, which should each provide an easier path for future binary input sources - A protobuf decoding library was included ([protobufjs](https://www.npmjs.com/package/protobufjs)) which includes both a protobuf parser generator based on a .proto file & TypeScript definition generation from the resulting generated JavaScript file - More generic binary file import. Before this PR, all supported sources were plaintext, with the exception of Instruments 10 support, which takes a totally different codepath. Now binary file import should work when files are dropped, opened via file browsing, or opened via invocation of the speedscope CLI. - Transparent gzip decoding of imported files (this means that if you were to gzip compress another JSON file, then importing it should still work fine) Fixes #60. -- This is a [donation motivated](https://github.com/jlfwong/speedscope/issues/60#issuecomment-419660710) PR motivated by donations by @davecheney & @jmoiron to [/dev/color](https://www.devcolor.org/welcome) 🎉 --- package-lock.json | 99 +- package.json | 1 + sample/profiles/pprof/simple.prof | Bin 0 -> 1101 bytes sample/programs/go/.gitignore | 2 + sample/programs/go/Makefile | 15 + sample/programs/go/server.go | 71 + sample/programs/go/simple.go | 53 + src/import/__snapshots__/pprof.test.ts.snap | 249 ++ src/import/index.test.ts | 8 +- src/import/index.ts | 52 +- src/import/instruments.ts | 50 +- src/import/pprof.test.ts | 5 + src/import/pprof.ts | 134 + src/import/profile.proto | 206 ++ src/import/profile.proto.d.ts | 1047 ++++++ src/import/profile.proto.js | 3543 +++++++++++++++++++ src/import/utils.ts | 83 + src/lib/test-utils.ts | 9 +- src/lib/utils.test.ts | 19 + src/lib/utils.ts | 128 + src/views/application.tsx | 55 +- 21 files changed, 5748 insertions(+), 81 deletions(-) create mode 100644 sample/profiles/pprof/simple.prof create mode 100644 sample/programs/go/.gitignore create mode 100644 sample/programs/go/Makefile create mode 100644 sample/programs/go/server.go create mode 100644 sample/programs/go/simple.go create mode 100644 src/import/__snapshots__/pprof.test.ts.snap create mode 100644 src/import/pprof.test.ts create mode 100644 src/import/pprof.ts create mode 100644 src/import/profile.proto create mode 100644 src/import/profile.proto.d.ts create mode 100644 src/import/profile.proto.js create mode 100644 src/import/utils.ts diff --git a/package-lock.json b/package-lock.json index 494cf2e..d5f86b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "speedscope", - "version": "0.7.0", + "version": "1.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -24,6 +24,70 @@ "js-tokens": "^3.0.0" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "dev": true + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "dev": true + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "dev": true + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "dev": true + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "dev": true + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "dev": true + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "dev": true + }, "@types/jest": { "version": "22.2.3", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-22.2.3.tgz", @@ -39,6 +103,12 @@ "@types/node": "*" } }, + "@types/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", + "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==", + "dev": true + }, "@types/node": { "version": "10.1.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.1.4.tgz", @@ -7502,6 +7572,12 @@ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "dev": true + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", @@ -10703,6 +10779,27 @@ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", "dev": true }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "dev": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", diff --git a/package.json b/package.json index 461e80e..3547232 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "preact": "8.2.7", "preact-redux": "jlfwong/preact-redux#a56dcc4", "prettier": "1.12.0", + "protobufjs": "6.8.8", "quicktype": "15.0.45", "redux": "^4.0.0", "ts-jest": "22.4.6", diff --git a/sample/profiles/pprof/simple.prof b/sample/profiles/pprof/simple.prof new file mode 100644 index 0000000000000000000000000000000000000000..574b4278b9c9494760974e92e999f7b77b4c832a GIT binary patch literal 1101 zcmV-T1hV@diwFP!00004|CEzWs2f!j$4w@AIhkZ8CzF@tE3s>Z)#B zir~i0b2_;%FLpk{+zHQz2mw*-hqkmn#1D`v7OS>y6zW2{sTFK32*rh*KQ{J4hG|1A~@1>B%MH?WC1u95Eq0={|prC65CoZ9aNQ~ zTCy}K(}}V3vQfqs4)49Qt}2*3tp#*tugOSqXm-$x2wKy4kQasM7GYW8xyqxYq_K zW0RU@!_vW^%jaJfEgGH`*P!NAru|&R%`$r=V;DUEgfd*t@ou;!4J^} zsNg)!OQlW^zLb}Yct=D-T%ZN1H0ayc<kV(9gv_7RqP?jh$H&JylCAFQs&QP=U~4s&>)u@3j+ zK66Gar=P^##0$C8jUC<-_;xpT)lhIcEJ!_f#1sX$oD8D07qZdnQD?vtCy0G7aGqd6 z;3WdG++IG=UUq`s5%vP}9iI5kc9-z-Cv-39uX)=}T`vqh7q>UIJA>6#Kkje1k56kM zI#;}~^T@$ApYS5K&Qs4n>OM9tPqvB7)p52kPMEB^ho*&jJlx5)xWn`OwH3}nufG;2 zY=!r_kr%j!r)BdEzS8lM^bnbK|EQdVaM5>MQZGqER~xSdy+2td% { // Importing garbage should return null - expect(await importProfileGroup('unknown', '')).toBe(null) - expect(await importProfileGroup('unknown', 'Hello world')).toBe(null) - expect(await importProfileGroup('unknown', 'Hello\n\nWorld')).toBe(null) + expect(await importProfileGroupFromText('unknown', '')).toBe(null) + expect(await importProfileGroupFromText('unknown', 'Hello world')).toBe(null) + expect(await importProfileGroupFromText('unknown', 'Hello\n\nWorld')).toBe(null) }) diff --git a/src/import/index.ts b/src/import/index.ts index 9c8db0b..553b6ba 100644 --- a/src/import/index.ts +++ b/src/import/index.ts @@ -9,12 +9,41 @@ import {importFromFirefox} from './firefox' import {importSpeedscopeProfiles} from '../lib/file-format' import {importFromV8ProfLog} from './v8proflog' import {importFromLinuxPerf} from './linux-tools-perf' +import {ProfileDataSource, TextProfileDataSource, MaybeCompressedDataReader} from './utils' +import {importAsPprofProfile} from './pprof' +import {decodeBase64} from '../lib/utils' -export async function importProfileGroup( +export async function importProfileGroupFromText( fileName: string, contents: string, ): Promise { - const profileGroup = await _importProfileGroup(fileName, contents) + return await importProfileGroup(new TextProfileDataSource(fileName, contents)) +} + +export async function importProfileGroupFromBase64( + fileName: string, + b64contents: string, +): Promise { + return await importProfileGroup( + MaybeCompressedDataReader.fromArrayBuffer(fileName, decodeBase64(b64contents).buffer), + ) +} + +export async function importProfilesFromFile(file: File): Promise { + return importProfileGroup(MaybeCompressedDataReader.fromFile(file)) +} + +export async function importProfilesFromArrayBuffer( + fileName: string, + buffer: ArrayBuffer, +): Promise { + return importProfileGroup(MaybeCompressedDataReader.fromArrayBuffer(fileName, buffer)) +} + +async function importProfileGroup(dataSource: ProfileDataSource): Promise { + const fileName = await dataSource.name() + + const profileGroup = await _importProfileGroup(dataSource) if (profileGroup) { if (!profileGroup.name) { profileGroup.name = fileName @@ -34,10 +63,21 @@ function toGroup(profile: Profile | null): ProfileGroup | null { return {name: profile.getName(), indexToView: 0, profiles: [profile]} } -async function _importProfileGroup( - fileName: string, - contents: string, -): Promise { +async function _importProfileGroup(dataSource: ProfileDataSource): Promise { + const fileName = await dataSource.name() + + const buffer = await dataSource.readAsArrayBuffer() + + { + const profile = importAsPprofProfile(buffer) + if (profile) { + console.log('Importing as protobuf encoded pprof file') + return toGroup(profile) + } + } + + const contents = await dataSource.readAsText() + // First pass: Check known file format names to infer the file type if (fileName.endsWith('.speedscope.json')) { console.log('Importing as speedscope json file') diff --git a/src/import/instruments.ts b/src/import/instruments.ts index 55d3bb9..c795568 100644 --- a/src/import/instruments.ts +++ b/src/import/instruments.ts @@ -9,9 +9,9 @@ import { ProfileGroup, } from '../lib/profile' import {sortBy, getOrThrow, getOrInsert, lastOf, getOrElse, zeroPad} from '../lib/utils' -import * as pako from 'pako' import {ByteFormatter, TimeFormatter} from '../lib/value-formatters' import {FileSystemDirectoryEntry, FileSystemEntry, FileSystemFileEntry} from './file-system-entry' +import {MaybeCompressedDataReader} from './utils' function parseTSV(contents: string): T[] { const lines = contents.split('\n').map(l => l.split('\t')) @@ -183,56 +183,12 @@ async function extractDirectoryTree(entry: FileSystemDirectoryEntry): Promise - - constructor(file: File) { - this.fileData = new Promise(resolve => { - const reader = new FileReader() - reader.addEventListener('loadend', () => { - if (!(reader.result instanceof ArrayBuffer)) { - throw new Error('Expected reader.result to be an instance of ArrayBuffer') - } - resolve(reader.result) - }) - reader.readAsArrayBuffer(file) - }) - } - - private async getUncompressed(): Promise { - const fileData = await this.fileData - try { - const result = pako.inflate(new Uint8Array(fileData)).buffer - return result - } catch (e) { - return fileData - } - } - - async readAsArrayBuffer(): Promise { - return await this.getUncompressed() - } - - async readAsText(): Promise { - const buffer = await this.getUncompressed() - let ret: string = '' - - // JavaScript strings are UTF-16 encoded, but this data is coming - // from a UTF-8 encoded file. - const array = new Uint8Array(buffer) - for (let i = 0; i < array.length; i++) { - ret += String.fromCharCode(array[i]) - } - return ret - } -} - function readAsArrayBuffer(file: File): Promise { - return new MaybeCompressedFileReader(file).readAsArrayBuffer() + return MaybeCompressedDataReader.fromFile(file).readAsArrayBuffer() } function readAsText(file: File): Promise { - return new MaybeCompressedFileReader(file).readAsText() + return MaybeCompressedDataReader.fromFile(file).readAsText() } function getCoreDirForRun(tree: TraceDirectoryTree, selectedRun: number): TraceDirectoryTree { diff --git a/src/import/pprof.test.ts b/src/import/pprof.test.ts new file mode 100644 index 0000000..41d08ba --- /dev/null +++ b/src/import/pprof.test.ts @@ -0,0 +1,5 @@ +import {checkProfileSnapshot} from '../lib/test-utils' + +test('importAsPprofProfile', async () => { + await checkProfileSnapshot('./sample/profiles/pprof/simple.prof') +}) diff --git a/src/import/pprof.ts b/src/import/pprof.ts new file mode 100644 index 0000000..1f02f79 --- /dev/null +++ b/src/import/pprof.ts @@ -0,0 +1,134 @@ +import {perftools} from './profile.proto.js' +import {FrameInfo, StackListProfileBuilder, Profile} from '../lib/profile' +import {lastOf} from '../lib/utils' +import {TimeFormatter, ByteFormatter} from '../lib/value-formatters' + +interface SampleType { + type: string + unit: string +} + +export function importAsPprofProfile(rawProfile: ArrayBuffer): Profile | null { + if (rawProfile.byteLength === 0) return null + + let protoProfile: perftools.profiles.Profile + try { + protoProfile = perftools.profiles.Profile.decode(new Uint8Array(rawProfile)) + } catch (e) { + return null + } + + function i32(n: number | Long): number { + return typeof n === 'number' ? n : (n as Long).low + } + + function stringVal(key: number | Long): string | null { + return protoProfile.stringTable[i32(key)] || null + } + + const frameInfoByFunctionID = new Map() + + function frameInfoForFunction(f: perftools.profiles.IFunction): FrameInfo | null { + const {name, filename, startLine} = f + + const nameString = (name != null && stringVal(name)) || '(unknown)' + const fileNameString = filename != null ? stringVal(filename) : null + const line = startLine != null ? +startLine : null + + const key = `${nameString}:${fileNameString}:${line}` + + const frameInfo: FrameInfo = { + key, + name: nameString, + } + + if (fileNameString != null) { + frameInfo.file = fileNameString + } + + if (line != null) { + frameInfo.line = line + } + + return frameInfo + } + + for (let f of protoProfile.function) { + if (f.id) { + const frameInfo = frameInfoForFunction(f) + if (frameInfo != null) { + frameInfoByFunctionID.set(i32(f.id), frameInfo) + } + } + } + + function frameInfoForLocation(location: perftools.profiles.ILocation): FrameInfo | null { + const {line} = location + if (line == null) return null + + // From a comment on profile.proto: + // + // Multiple line indicates this location has inlined functions, + // where the last entry represents the caller into which the + // preceding entries were inlined. + // + // E.g., if memcpy() is inlined into printf: + // line[0].function_name == "memcpy" + // line[1].function_name == "printf" + // + // Let's just take the last line then + const lastLine = lastOf(line) + if (lastLine == null) return null + + if (lastLine.functionId) { + return frameInfoByFunctionID.get(i32(lastLine.functionId)) || null + } else { + return null + } + } + + const frameByLocationID = new Map() + + for (let l of protoProfile.location) { + if (l.id != null) { + const frameInfo = frameInfoForLocation(l) + if (frameInfo) { + frameByLocationID.set(i32(l.id), frameInfo) + } + } + } + + const sampleTypes: SampleType[] = protoProfile.sampleType.map(type => ({ + type: (type.type && stringVal(type.type)) || 'samples', + unit: (type.unit && stringVal(type.unit)) || 'count', + })) + + const sampleTypeIndex = protoProfile.defaultSampleType + ? +protoProfile.defaultSampleType + : sampleTypes.length - 1 + const sampleType = sampleTypes[sampleTypeIndex] + + const profileBuilder = new StackListProfileBuilder() + + switch (sampleType.unit) { + case 'nanoseconds': + case 'microseconds': + case 'milliseconds': + case 'seconds': + profileBuilder.setValueFormatter(new TimeFormatter(sampleType.unit)) + break + + case 'bytes': + profileBuilder.setValueFormatter(new ByteFormatter()) + break + } + + for (let s of protoProfile.sample) { + const stack = s.locationId ? s.locationId.map(l => frameByLocationID.get(i32(l))) : [] + stack.reverse() + const value = s.value![sampleTypeIndex] + profileBuilder.appendSampleWithWeight(stack.filter(f => f != null) as FrameInfo[], +value) + } + + return profileBuilder.build() +} diff --git a/src/import/profile.proto b/src/import/profile.proto new file mode 100644 index 0000000..a6e6a89 --- /dev/null +++ b/src/import/profile.proto @@ -0,0 +1,206 @@ +// THIS FILE WAS IMPORTED FROM AN EXTERNAL SOURCE. DO NOT MODIFY THIS FILE +// MANUALLY. +// +// Original from: https://github.com/google/pprof/blob/e027b50/proto/profile.proto +// +// This file is licensed under the Apache License 2.0 +// (https://github.com/google/pprof/blob/e027b5/LICENSE) + +// Profile is a common stacktrace profile format. +// +// Measurements represented with this format should follow the +// following conventions: +// +// - Consumers should treat unset optional fields as if they had been +// set with their default value. +// +// - When possible, measurements should be stored in "unsampled" form +// that is most useful to humans. There should be enough +// information present to determine the original sampled values. +// +// - On-disk, the serialized proto must be gzip-compressed. +// +// - The profile is represented as a set of samples, where each sample +// references a sequence of locations, and where each location belongs +// to a mapping. +// - There is a N->1 relationship from sample.location_id entries to +// locations. For every sample.location_id entry there must be a +// unique Location with that id. +// - There is an optional N->1 relationship from locations to +// mappings. For every nonzero Location.mapping_id there must be a +// unique Mapping with that id. + +syntax = "proto3"; + +package perftools.profiles; + +option java_package = "com.google.perftools.profiles"; +option java_outer_classname = "ProfileProto"; + +message Profile { + // A description of the samples associated with each Sample.value. + // For a cpu profile this might be: + // [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]] + // For a heap profile, this might be: + // [["allocations","count"], ["space","bytes"]], + // If one of the values represents the number of events represented + // by the sample, by convention it should be at index 0 and use + // sample_type.unit == "count". + repeated ValueType sample_type = 1; + // The set of samples recorded in this profile. + repeated Sample sample = 2; + // Mapping from address ranges to the image/binary/library mapped + // into that address range. mapping[0] will be the main binary. + repeated Mapping mapping = 3; + // Useful program location + repeated Location location = 4; + // Functions referenced by locations + repeated Function function = 5; + // A common table for strings referenced by various messages. + // string_table[0] must always be "". + repeated string string_table = 6; + // frames with Function.function_name fully matching the following + // regexp will be dropped from the samples, along with their successors. + int64 drop_frames = 7; // Index into string table. + // frames with Function.function_name fully matching the following + // regexp will be kept, even if it matches drop_functions. + int64 keep_frames = 8; // Index into string table. + + // The following fields are informational, do not affect + // interpretation of results. + + // Time of collection (UTC) represented as nanoseconds past the epoch. + int64 time_nanos = 9; + // Duration of the profile, if a duration makes sense. + int64 duration_nanos = 10; + // The kind of events between sampled ocurrences. + // e.g [ "cpu","cycles" ] or [ "heap","bytes" ] + ValueType period_type = 11; + // The number of events between sampled occurrences. + int64 period = 12; + // Freeform text associated to the profile. + repeated int64 comment = 13; // Indices into string table. + // Index into the string table of the type of the preferred sample + // value. If unset, clients should default to the last sample value. + int64 default_sample_type = 14; +} + +// ValueType describes the semantics and measurement units of a value. +message ValueType { + int64 type = 1; // Index into string table. + int64 unit = 2; // Index into string table. +} + +// Each Sample records values encountered in some program +// context. The program context is typically a stack trace, perhaps +// augmented with auxiliary information like the thread-id, some +// indicator of a higher level request being handled etc. +message Sample { + // The ids recorded here correspond to a Profile.location.id. + // The leaf is at location_id[0]. + repeated uint64 location_id = 1; + // The type and unit of each value is defined by the corresponding + // entry in Profile.sample_type. All samples must have the same + // number of values, the same as the length of Profile.sample_type. + // When aggregating multiple samples into a single sample, the + // result has a list of values that is the elemntwise sum of the + // lists of the originals. + repeated int64 value = 2; + // label includes additional context for this sample. It can include + // things like a thread id, allocation size, etc + repeated Label label = 3; +} + +message Label { + int64 key = 1; // Index into string table + + // At most one of the following must be present + int64 str = 2; // Index into string table + int64 num = 3; + + // Should only be present when num is present. + // Specifies the units of num. + // Use arbitrary string (for example, "requests") as a custom count unit. + // If no unit is specified, consumer may apply heuristic to deduce the unit. + // Consumers may also interpret units like "bytes" and "kilobytes" as memory + // units and units like "seconds" and "nanoseconds" as time units, + // and apply appropriate unit conversions to these. + int64 num_unit = 4; // Index into string table +} + +message Mapping { + // Unique nonzero id for the mapping. + uint64 id = 1; + // Address at which the binary (or DLL) is loaded into memory. + uint64 memory_start = 2; + // The limit of the address range occupied by this mapping. + uint64 memory_limit = 3; + // Offset in the binary that corresponds to the first mapped address. + uint64 file_offset = 4; + // The object this entry is loaded from. This can be a filename on + // disk for the main binary and shared libraries, or virtual + // abstractions like "[vdso]". + int64 filename = 5; // Index into string table + // A string that uniquely identifies a particular program version + // with high probability. E.g., for binaries generated by GNU tools, + // it could be the contents of the .note.gnu.build-id field. + int64 build_id = 6; // Index into string table + + // The following fields indicate the resolution of symbolic info. + bool has_functions = 7; + bool has_filenames = 8; + bool has_line_numbers = 9; + bool has_inline_frames = 10; +} + +// Describes function and line table debug information. +message Location { + // Unique nonzero id for the location. A profile could use + // instruction addresses or any integer sequence as ids. + uint64 id = 1; + // The id of the corresponding profile.Mapping for this location. + // It can be unset if the mapping is unknown or not applicable for + // this profile type. + uint64 mapping_id = 2; + // The instruction address for this location, if available. It + // should be within [Mapping.memory_start...Mapping.memory_limit] + // for the corresponding mapping. A non-leaf address may be in the + // middle of a call instruction. It is up to display tools to find + // the beginning of the instruction if necessary. + uint64 address = 3; + // Multiple line indicates this location has inlined functions, + // where the last entry represents the caller into which the + // preceding entries were inlined. + // + // E.g., if memcpy() is inlined into printf: + // line[0].function_name == "memcpy" + // line[1].function_name == "printf" + repeated Line line = 4; + // Provides an indication that multiple symbols map to this location's + // address, for example due to identical code folding by the linker. In that + // case the line information above represents one of the multiple + // symbols. This field must be recomputed when the symbolization state of the + // profile changes. + bool is_folded = 5; +} + +message Line { + // The id of the corresponding profile.Function for this line. + uint64 function_id = 1; + // Line number in source code. + int64 line = 2; +} + +message Function { + // Unique nonzero id for the function. + uint64 id = 1; + // Name of the function, in human-readable form if available. + int64 name = 2; // Index into string table + // Name of the function, as identified by the system. + // For instance, it can be a C++ mangled name. + int64 system_name = 3; // Index into string table + // Source file containing the function. + int64 filename = 4; // Index into string table + // Line number in source file. + int64 start_line = 5; +} \ No newline at end of file diff --git a/src/import/profile.proto.d.ts b/src/import/profile.proto.d.ts new file mode 100644 index 0000000..1721b8e --- /dev/null +++ b/src/import/profile.proto.d.ts @@ -0,0 +1,1047 @@ +// THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY THIS FILE MANUALLY. +// +// To regenerate this file, run the following in the repository root: +// +// node node_modules/protobufjs/cli/bin/pbts -o src/import/profile.proto.d.ts src/import/profile.proto.j +// +// Then prepend this comment to the result. +import * as $protobuf from 'protobufjs' +/** Namespace perftools. */ +export namespace perftools { + /** Namespace profiles. */ + namespace profiles { + /** Properties of a Profile. */ + interface IProfile { + /** Profile sampleType */ + sampleType?: perftools.profiles.IValueType[] | null + + /** Profile sample */ + sample?: perftools.profiles.ISample[] | null + + /** Profile mapping */ + mapping?: perftools.profiles.IMapping[] | null + + /** Profile location */ + location?: perftools.profiles.ILocation[] | null + + /** Profile function */ + function?: perftools.profiles.IFunction[] | null + + /** Profile stringTable */ + stringTable?: string[] | null + + /** Profile dropFrames */ + dropFrames?: number | Long | null + + /** Profile keepFrames */ + keepFrames?: number | Long | null + + /** Profile timeNanos */ + timeNanos?: number | Long | null + + /** Profile durationNanos */ + durationNanos?: number | Long | null + + /** Profile periodType */ + periodType?: perftools.profiles.IValueType | null + + /** Profile period */ + period?: number | Long | null + + /** Profile comment */ + comment?: (number | Long)[] | null + + /** Profile defaultSampleType */ + defaultSampleType?: number | Long | null + } + + /** Represents a Profile. */ + class Profile implements IProfile { + /** + * Constructs a new Profile. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.IProfile) + + /** Profile sampleType. */ + public sampleType: perftools.profiles.IValueType[] + + /** Profile sample. */ + public sample: perftools.profiles.ISample[] + + /** Profile mapping. */ + public mapping: perftools.profiles.IMapping[] + + /** Profile location. */ + public location: perftools.profiles.ILocation[] + + /** Profile function. */ + public function: perftools.profiles.IFunction[] + + /** Profile stringTable. */ + public stringTable: string[] + + /** Profile dropFrames. */ + public dropFrames: number | Long + + /** Profile keepFrames. */ + public keepFrames: number | Long + + /** Profile timeNanos. */ + public timeNanos: number | Long + + /** Profile durationNanos. */ + public durationNanos: number | Long + + /** Profile periodType. */ + public periodType?: perftools.profiles.IValueType | null + + /** Profile period. */ + public period: number | Long + + /** Profile comment. */ + public comment: (number | Long)[] + + /** Profile defaultSampleType. */ + public defaultSampleType: number | Long + + /** + * Creates a new Profile instance using the specified properties. + * @param [properties] Properties to set + * @returns Profile instance + */ + public static create(properties?: perftools.profiles.IProfile): perftools.profiles.Profile + + /** + * Encodes the specified Profile message. Does not implicitly {@link perftools.profiles.Profile.verify|verify} messages. + * @param message Profile message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.IProfile, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Profile message, length delimited. Does not implicitly {@link perftools.profiles.Profile.verify|verify} messages. + * @param message Profile message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.IProfile, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Profile message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Profile + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Profile + + /** + * Decodes a Profile message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Profile + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited( + reader: $protobuf.Reader | Uint8Array, + ): perftools.profiles.Profile + + /** + * Verifies a Profile message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Profile message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Profile + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Profile + + /** + * Creates a plain object from a Profile message. Also converts values to other types if specified. + * @param message Profile + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Profile, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Profile to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a ValueType. */ + interface IValueType { + /** ValueType type */ + type?: number | Long | null + + /** ValueType unit */ + unit?: number | Long | null + } + + /** Represents a ValueType. */ + class ValueType implements IValueType { + /** + * Constructs a new ValueType. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.IValueType) + + /** ValueType type. */ + public type: number | Long + + /** ValueType unit. */ + public unit: number | Long + + /** + * Creates a new ValueType instance using the specified properties. + * @param [properties] Properties to set + * @returns ValueType instance + */ + public static create(properties?: perftools.profiles.IValueType): perftools.profiles.ValueType + + /** + * Encodes the specified ValueType message. Does not implicitly {@link perftools.profiles.ValueType.verify|verify} messages. + * @param message ValueType message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.IValueType, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified ValueType message, length delimited. Does not implicitly {@link perftools.profiles.ValueType.verify|verify} messages. + * @param message ValueType message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.IValueType, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a ValueType message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns ValueType + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.ValueType + + /** + * Decodes a ValueType message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns ValueType + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited( + reader: $protobuf.Reader | Uint8Array, + ): perftools.profiles.ValueType + + /** + * Verifies a ValueType message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a ValueType message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns ValueType + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.ValueType + + /** + * Creates a plain object from a ValueType message. Also converts values to other types if specified. + * @param message ValueType + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.ValueType, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this ValueType to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a Sample. */ + interface ISample { + /** Sample locationId */ + locationId?: (number | Long)[] | null + + /** Sample value */ + value?: (number | Long)[] | null + + /** Sample label */ + label?: perftools.profiles.ILabel[] | null + } + + /** Represents a Sample. */ + class Sample implements ISample { + /** + * Constructs a new Sample. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.ISample) + + /** Sample locationId. */ + public locationId: (number | Long)[] + + /** Sample value. */ + public value: (number | Long)[] + + /** Sample label. */ + public label: perftools.profiles.ILabel[] + + /** + * Creates a new Sample instance using the specified properties. + * @param [properties] Properties to set + * @returns Sample instance + */ + public static create(properties?: perftools.profiles.ISample): perftools.profiles.Sample + + /** + * Encodes the specified Sample message. Does not implicitly {@link perftools.profiles.Sample.verify|verify} messages. + * @param message Sample message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.ISample, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Sample message, length delimited. Does not implicitly {@link perftools.profiles.Sample.verify|verify} messages. + * @param message Sample message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.ISample, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Sample message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Sample + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Sample + + /** + * Decodes a Sample message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Sample + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited( + reader: $protobuf.Reader | Uint8Array, + ): perftools.profiles.Sample + + /** + * Verifies a Sample message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Sample message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Sample + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Sample + + /** + * Creates a plain object from a Sample message. Also converts values to other types if specified. + * @param message Sample + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Sample, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Sample to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a Label. */ + interface ILabel { + /** Label key */ + key?: number | Long | null + + /** Label str */ + str?: number | Long | null + + /** Label num */ + num?: number | Long | null + + /** Label numUnit */ + numUnit?: number | Long | null + } + + /** Represents a Label. */ + class Label implements ILabel { + /** + * Constructs a new Label. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.ILabel) + + /** Label key. */ + public key: number | Long + + /** Label str. */ + public str: number | Long + + /** Label num. */ + public num: number | Long + + /** Label numUnit. */ + public numUnit: number | Long + + /** + * Creates a new Label instance using the specified properties. + * @param [properties] Properties to set + * @returns Label instance + */ + public static create(properties?: perftools.profiles.ILabel): perftools.profiles.Label + + /** + * Encodes the specified Label message. Does not implicitly {@link perftools.profiles.Label.verify|verify} messages. + * @param message Label message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.ILabel, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Label message, length delimited. Does not implicitly {@link perftools.profiles.Label.verify|verify} messages. + * @param message Label message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.ILabel, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Label message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Label + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Label + + /** + * Decodes a Label message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Label + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: $protobuf.Reader | Uint8Array): perftools.profiles.Label + + /** + * Verifies a Label message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Label message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Label + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Label + + /** + * Creates a plain object from a Label message. Also converts values to other types if specified. + * @param message Label + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Label, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Label to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a Mapping. */ + interface IMapping { + /** Mapping id */ + id?: number | Long | null + + /** Mapping memoryStart */ + memoryStart?: number | Long | null + + /** Mapping memoryLimit */ + memoryLimit?: number | Long | null + + /** Mapping fileOffset */ + fileOffset?: number | Long | null + + /** Mapping filename */ + filename?: number | Long | null + + /** Mapping buildId */ + buildId?: number | Long | null + + /** Mapping hasFunctions */ + hasFunctions?: boolean | null + + /** Mapping hasFilenames */ + hasFilenames?: boolean | null + + /** Mapping hasLineNumbers */ + hasLineNumbers?: boolean | null + + /** Mapping hasInlineFrames */ + hasInlineFrames?: boolean | null + } + + /** Represents a Mapping. */ + class Mapping implements IMapping { + /** + * Constructs a new Mapping. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.IMapping) + + /** Mapping id. */ + public id: number | Long + + /** Mapping memoryStart. */ + public memoryStart: number | Long + + /** Mapping memoryLimit. */ + public memoryLimit: number | Long + + /** Mapping fileOffset. */ + public fileOffset: number | Long + + /** Mapping filename. */ + public filename: number | Long + + /** Mapping buildId. */ + public buildId: number | Long + + /** Mapping hasFunctions. */ + public hasFunctions: boolean + + /** Mapping hasFilenames. */ + public hasFilenames: boolean + + /** Mapping hasLineNumbers. */ + public hasLineNumbers: boolean + + /** Mapping hasInlineFrames. */ + public hasInlineFrames: boolean + + /** + * Creates a new Mapping instance using the specified properties. + * @param [properties] Properties to set + * @returns Mapping instance + */ + public static create(properties?: perftools.profiles.IMapping): perftools.profiles.Mapping + + /** + * Encodes the specified Mapping message. Does not implicitly {@link perftools.profiles.Mapping.verify|verify} messages. + * @param message Mapping message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.IMapping, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Mapping message, length delimited. Does not implicitly {@link perftools.profiles.Mapping.verify|verify} messages. + * @param message Mapping message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.IMapping, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Mapping message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Mapping + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Mapping + + /** + * Decodes a Mapping message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Mapping + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited( + reader: $protobuf.Reader | Uint8Array, + ): perftools.profiles.Mapping + + /** + * Verifies a Mapping message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Mapping message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Mapping + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Mapping + + /** + * Creates a plain object from a Mapping message. Also converts values to other types if specified. + * @param message Mapping + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Mapping, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Mapping to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a Location. */ + interface ILocation { + /** Location id */ + id?: number | Long | null + + /** Location mappingId */ + mappingId?: number | Long | null + + /** Location address */ + address?: number | Long | null + + /** Location line */ + line?: perftools.profiles.ILine[] | null + + /** Location isFolded */ + isFolded?: boolean | null + } + + /** Represents a Location. */ + class Location implements ILocation { + /** + * Constructs a new Location. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.ILocation) + + /** Location id. */ + public id: number | Long + + /** Location mappingId. */ + public mappingId: number | Long + + /** Location address. */ + public address: number | Long + + /** Location line. */ + public line: perftools.profiles.ILine[] + + /** Location isFolded. */ + public isFolded: boolean + + /** + * Creates a new Location instance using the specified properties. + * @param [properties] Properties to set + * @returns Location instance + */ + public static create(properties?: perftools.profiles.ILocation): perftools.profiles.Location + + /** + * Encodes the specified Location message. Does not implicitly {@link perftools.profiles.Location.verify|verify} messages. + * @param message Location message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.ILocation, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Location message, length delimited. Does not implicitly {@link perftools.profiles.Location.verify|verify} messages. + * @param message Location message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.ILocation, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Location message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Location + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Location + + /** + * Decodes a Location message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Location + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited( + reader: $protobuf.Reader | Uint8Array, + ): perftools.profiles.Location + + /** + * Verifies a Location message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Location message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Location + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Location + + /** + * Creates a plain object from a Location message. Also converts values to other types if specified. + * @param message Location + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Location, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Location to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a Line. */ + interface ILine { + /** Line functionId */ + functionId?: number | Long | null + + /** Line line */ + line?: number | Long | null + } + + /** Represents a Line. */ + class Line implements ILine { + /** + * Constructs a new Line. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.ILine) + + /** Line functionId. */ + public functionId: number | Long + + /** Line line. */ + public line: number | Long + + /** + * Creates a new Line instance using the specified properties. + * @param [properties] Properties to set + * @returns Line instance + */ + public static create(properties?: perftools.profiles.ILine): perftools.profiles.Line + + /** + * Encodes the specified Line message. Does not implicitly {@link perftools.profiles.Line.verify|verify} messages. + * @param message Line message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.ILine, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Line message, length delimited. Does not implicitly {@link perftools.profiles.Line.verify|verify} messages. + * @param message Line message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.ILine, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Line message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Line + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Line + + /** + * Decodes a Line message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Line + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: $protobuf.Reader | Uint8Array): perftools.profiles.Line + + /** + * Verifies a Line message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Line message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Line + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Line + + /** + * Creates a plain object from a Line message. Also converts values to other types if specified. + * @param message Line + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Line, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Line to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + + /** Properties of a Function. */ + interface IFunction { + /** Function id */ + id?: number | Long | null + + /** Function name */ + name?: number | Long | null + + /** Function systemName */ + systemName?: number | Long | null + + /** Function filename */ + filename?: number | Long | null + + /** Function startLine */ + startLine?: number | Long | null + } + + /** Represents a Function. */ + class Function implements IFunction { + /** + * Constructs a new Function. + * @param [properties] Properties to set + */ + constructor(properties?: perftools.profiles.IFunction) + + /** Function id. */ + public id: number | Long + + /** Function name. */ + public name: number | Long + + /** Function systemName. */ + public systemName: number | Long + + /** Function filename. */ + public filename: number | Long + + /** Function startLine. */ + public startLine: number | Long + + /** + * Creates a new Function instance using the specified properties. + * @param [properties] Properties to set + * @returns Function instance + */ + public static create(properties?: perftools.profiles.IFunction): perftools.profiles.Function + + /** + * Encodes the specified Function message. Does not implicitly {@link perftools.profiles.Function.verify|verify} messages. + * @param message Function message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode( + message: perftools.profiles.IFunction, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Encodes the specified Function message, length delimited. Does not implicitly {@link perftools.profiles.Function.verify|verify} messages. + * @param message Function message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited( + message: perftools.profiles.IFunction, + writer?: $protobuf.Writer, + ): $protobuf.Writer + + /** + * Decodes a Function message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Function + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode( + reader: $protobuf.Reader | Uint8Array, + length?: number, + ): perftools.profiles.Function + + /** + * Decodes a Function message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Function + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited( + reader: $protobuf.Reader | Uint8Array, + ): perftools.profiles.Function + + /** + * Verifies a Function message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): string | null + + /** + * Creates a Function message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Function + */ + public static fromObject(object: {[k: string]: any}): perftools.profiles.Function + + /** + * Creates a plain object from a Function message. Also converts values to other types if specified. + * @param message Function + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject( + message: perftools.profiles.Function, + options?: $protobuf.IConversionOptions, + ): {[k: string]: any} + + /** + * Converts this Function to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any} + } + } +} diff --git a/src/import/profile.proto.js b/src/import/profile.proto.js new file mode 100644 index 0000000..b8252da --- /dev/null +++ b/src/import/profile.proto.js @@ -0,0 +1,3543 @@ +// THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY THIS FILE MANUALLY. +// +// To regenerate this file, run the following in the repository root: +// +// node node_modules/protobufjs/cli/bin/pbjs -t static-module -w commonjs -o src/import/profile.proto.js src/import/profile.proto +// +// Then prepend this comment to the result. +/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/ +'use strict' + +var $protobuf = require('protobufjs/minimal') + +// Common aliases +var $Reader = $protobuf.Reader, + $Writer = $protobuf.Writer, + $util = $protobuf.util + +// Exported root namespace +var $root = $protobuf.roots['default'] || ($protobuf.roots['default'] = {}) + +$root.perftools = (function() { + /** + * Namespace perftools. + * @exports perftools + * @namespace + */ + var perftools = {} + + perftools.profiles = (function() { + /** + * Namespace profiles. + * @memberof perftools + * @namespace + */ + var profiles = {} + + profiles.Profile = (function() { + /** + * Properties of a Profile. + * @memberof perftools.profiles + * @interface IProfile + * @property {Array.|null} [sampleType] Profile sampleType + * @property {Array.|null} [sample] Profile sample + * @property {Array.|null} [mapping] Profile mapping + * @property {Array.|null} [location] Profile location + * @property {Array.|null} ["function"] Profile function + * @property {Array.|null} [stringTable] Profile stringTable + * @property {number|Long|null} [dropFrames] Profile dropFrames + * @property {number|Long|null} [keepFrames] Profile keepFrames + * @property {number|Long|null} [timeNanos] Profile timeNanos + * @property {number|Long|null} [durationNanos] Profile durationNanos + * @property {perftools.profiles.IValueType|null} [periodType] Profile periodType + * @property {number|Long|null} [period] Profile period + * @property {Array.|null} [comment] Profile comment + * @property {number|Long|null} [defaultSampleType] Profile defaultSampleType + */ + + /** + * Constructs a new Profile. + * @memberof perftools.profiles + * @classdesc Represents a Profile. + * @implements IProfile + * @constructor + * @param {perftools.profiles.IProfile=} [properties] Properties to set + */ + function Profile(properties) { + this.sampleType = [] + this.sample = [] + this.mapping = [] + this.location = [] + this['function'] = [] + this.stringTable = [] + this.comment = [] + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Profile sampleType. + * @member {Array.} sampleType + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.sampleType = $util.emptyArray + + /** + * Profile sample. + * @member {Array.} sample + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.sample = $util.emptyArray + + /** + * Profile mapping. + * @member {Array.} mapping + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.mapping = $util.emptyArray + + /** + * Profile location. + * @member {Array.} location + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.location = $util.emptyArray + + /** + * Profile function. + * @member {Array.} function + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype['function'] = $util.emptyArray + + /** + * Profile stringTable. + * @member {Array.} stringTable + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.stringTable = $util.emptyArray + + /** + * Profile dropFrames. + * @member {number|Long} dropFrames + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.dropFrames = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Profile keepFrames. + * @member {number|Long} keepFrames + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.keepFrames = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Profile timeNanos. + * @member {number|Long} timeNanos + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.timeNanos = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Profile durationNanos. + * @member {number|Long} durationNanos + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.durationNanos = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Profile periodType. + * @member {perftools.profiles.IValueType|null|undefined} periodType + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.periodType = null + + /** + * Profile period. + * @member {number|Long} period + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.period = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Profile comment. + * @member {Array.} comment + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.comment = $util.emptyArray + + /** + * Profile defaultSampleType. + * @member {number|Long} defaultSampleType + * @memberof perftools.profiles.Profile + * @instance + */ + Profile.prototype.defaultSampleType = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Creates a new Profile instance using the specified properties. + * @function create + * @memberof perftools.profiles.Profile + * @static + * @param {perftools.profiles.IProfile=} [properties] Properties to set + * @returns {perftools.profiles.Profile} Profile instance + */ + Profile.create = function create(properties) { + return new Profile(properties) + } + + /** + * Encodes the specified Profile message. Does not implicitly {@link perftools.profiles.Profile.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Profile + * @static + * @param {perftools.profiles.IProfile} message Profile message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Profile.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.sampleType != null && message.sampleType.length) + for (var i = 0; i < message.sampleType.length; ++i) + $root.perftools.profiles.ValueType.encode( + message.sampleType[i], + writer.uint32(/* id 1, wireType 2 =*/ 10).fork(), + ).ldelim() + if (message.sample != null && message.sample.length) + for (var i = 0; i < message.sample.length; ++i) + $root.perftools.profiles.Sample.encode( + message.sample[i], + writer.uint32(/* id 2, wireType 2 =*/ 18).fork(), + ).ldelim() + if (message.mapping != null && message.mapping.length) + for (var i = 0; i < message.mapping.length; ++i) + $root.perftools.profiles.Mapping.encode( + message.mapping[i], + writer.uint32(/* id 3, wireType 2 =*/ 26).fork(), + ).ldelim() + if (message.location != null && message.location.length) + for (var i = 0; i < message.location.length; ++i) + $root.perftools.profiles.Location.encode( + message.location[i], + writer.uint32(/* id 4, wireType 2 =*/ 34).fork(), + ).ldelim() + if (message['function'] != null && message['function'].length) + for (var i = 0; i < message['function'].length; ++i) + $root.perftools.profiles.Function.encode( + message['function'][i], + writer.uint32(/* id 5, wireType 2 =*/ 42).fork(), + ).ldelim() + if (message.stringTable != null && message.stringTable.length) + for (var i = 0; i < message.stringTable.length; ++i) + writer.uint32(/* id 6, wireType 2 =*/ 50).string(message.stringTable[i]) + if (message.dropFrames != null && message.hasOwnProperty('dropFrames')) + writer.uint32(/* id 7, wireType 0 =*/ 56).int64(message.dropFrames) + if (message.keepFrames != null && message.hasOwnProperty('keepFrames')) + writer.uint32(/* id 8, wireType 0 =*/ 64).int64(message.keepFrames) + if (message.timeNanos != null && message.hasOwnProperty('timeNanos')) + writer.uint32(/* id 9, wireType 0 =*/ 72).int64(message.timeNanos) + if (message.durationNanos != null && message.hasOwnProperty('durationNanos')) + writer.uint32(/* id 10, wireType 0 =*/ 80).int64(message.durationNanos) + if (message.periodType != null && message.hasOwnProperty('periodType')) + $root.perftools.profiles.ValueType.encode( + message.periodType, + writer.uint32(/* id 11, wireType 2 =*/ 90).fork(), + ).ldelim() + if (message.period != null && message.hasOwnProperty('period')) + writer.uint32(/* id 12, wireType 0 =*/ 96).int64(message.period) + if (message.comment != null && message.comment.length) { + writer.uint32(/* id 13, wireType 2 =*/ 106).fork() + for (var i = 0; i < message.comment.length; ++i) writer.int64(message.comment[i]) + writer.ldelim() + } + if (message.defaultSampleType != null && message.hasOwnProperty('defaultSampleType')) + writer.uint32(/* id 14, wireType 0 =*/ 112).int64(message.defaultSampleType) + return writer + } + + /** + * Encodes the specified Profile message, length delimited. Does not implicitly {@link perftools.profiles.Profile.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Profile + * @static + * @param {perftools.profiles.IProfile} message Profile message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Profile.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Profile message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Profile + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Profile} Profile + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Profile.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Profile() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + if (!(message.sampleType && message.sampleType.length)) message.sampleType = [] + message.sampleType.push( + $root.perftools.profiles.ValueType.decode(reader, reader.uint32()), + ) + break + case 2: + if (!(message.sample && message.sample.length)) message.sample = [] + message.sample.push($root.perftools.profiles.Sample.decode(reader, reader.uint32())) + break + case 3: + if (!(message.mapping && message.mapping.length)) message.mapping = [] + message.mapping.push($root.perftools.profiles.Mapping.decode(reader, reader.uint32())) + break + case 4: + if (!(message.location && message.location.length)) message.location = [] + message.location.push( + $root.perftools.profiles.Location.decode(reader, reader.uint32()), + ) + break + case 5: + if (!(message['function'] && message['function'].length)) message['function'] = [] + message['function'].push( + $root.perftools.profiles.Function.decode(reader, reader.uint32()), + ) + break + case 6: + if (!(message.stringTable && message.stringTable.length)) message.stringTable = [] + message.stringTable.push(reader.string()) + break + case 7: + message.dropFrames = reader.int64() + break + case 8: + message.keepFrames = reader.int64() + break + case 9: + message.timeNanos = reader.int64() + break + case 10: + message.durationNanos = reader.int64() + break + case 11: + message.periodType = $root.perftools.profiles.ValueType.decode( + reader, + reader.uint32(), + ) + break + case 12: + message.period = reader.int64() + break + case 13: + if (!(message.comment && message.comment.length)) message.comment = [] + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos + while (reader.pos < end2) message.comment.push(reader.int64()) + } else message.comment.push(reader.int64()) + break + case 14: + message.defaultSampleType = reader.int64() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Profile message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Profile + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Profile} Profile + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Profile.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Profile message. + * @function verify + * @memberof perftools.profiles.Profile + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Profile.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.sampleType != null && message.hasOwnProperty('sampleType')) { + if (!Array.isArray(message.sampleType)) return 'sampleType: array expected' + for (var i = 0; i < message.sampleType.length; ++i) { + var error = $root.perftools.profiles.ValueType.verify(message.sampleType[i]) + if (error) return 'sampleType.' + error + } + } + if (message.sample != null && message.hasOwnProperty('sample')) { + if (!Array.isArray(message.sample)) return 'sample: array expected' + for (var i = 0; i < message.sample.length; ++i) { + var error = $root.perftools.profiles.Sample.verify(message.sample[i]) + if (error) return 'sample.' + error + } + } + if (message.mapping != null && message.hasOwnProperty('mapping')) { + if (!Array.isArray(message.mapping)) return 'mapping: array expected' + for (var i = 0; i < message.mapping.length; ++i) { + var error = $root.perftools.profiles.Mapping.verify(message.mapping[i]) + if (error) return 'mapping.' + error + } + } + if (message.location != null && message.hasOwnProperty('location')) { + if (!Array.isArray(message.location)) return 'location: array expected' + for (var i = 0; i < message.location.length; ++i) { + var error = $root.perftools.profiles.Location.verify(message.location[i]) + if (error) return 'location.' + error + } + } + if (message['function'] != null && message.hasOwnProperty('function')) { + if (!Array.isArray(message['function'])) return 'function: array expected' + for (var i = 0; i < message['function'].length; ++i) { + var error = $root.perftools.profiles.Function.verify(message['function'][i]) + if (error) return 'function.' + error + } + } + if (message.stringTable != null && message.hasOwnProperty('stringTable')) { + if (!Array.isArray(message.stringTable)) return 'stringTable: array expected' + for (var i = 0; i < message.stringTable.length; ++i) + if (!$util.isString(message.stringTable[i])) return 'stringTable: string[] expected' + } + if (message.dropFrames != null && message.hasOwnProperty('dropFrames')) + if ( + !$util.isInteger(message.dropFrames) && + !( + message.dropFrames && + $util.isInteger(message.dropFrames.low) && + $util.isInteger(message.dropFrames.high) + ) + ) + return 'dropFrames: integer|Long expected' + if (message.keepFrames != null && message.hasOwnProperty('keepFrames')) + if ( + !$util.isInteger(message.keepFrames) && + !( + message.keepFrames && + $util.isInteger(message.keepFrames.low) && + $util.isInteger(message.keepFrames.high) + ) + ) + return 'keepFrames: integer|Long expected' + if (message.timeNanos != null && message.hasOwnProperty('timeNanos')) + if ( + !$util.isInteger(message.timeNanos) && + !( + message.timeNanos && + $util.isInteger(message.timeNanos.low) && + $util.isInteger(message.timeNanos.high) + ) + ) + return 'timeNanos: integer|Long expected' + if (message.durationNanos != null && message.hasOwnProperty('durationNanos')) + if ( + !$util.isInteger(message.durationNanos) && + !( + message.durationNanos && + $util.isInteger(message.durationNanos.low) && + $util.isInteger(message.durationNanos.high) + ) + ) + return 'durationNanos: integer|Long expected' + if (message.periodType != null && message.hasOwnProperty('periodType')) { + var error = $root.perftools.profiles.ValueType.verify(message.periodType) + if (error) return 'periodType.' + error + } + if (message.period != null && message.hasOwnProperty('period')) + if ( + !$util.isInteger(message.period) && + !( + message.period && + $util.isInteger(message.period.low) && + $util.isInteger(message.period.high) + ) + ) + return 'period: integer|Long expected' + if (message.comment != null && message.hasOwnProperty('comment')) { + if (!Array.isArray(message.comment)) return 'comment: array expected' + for (var i = 0; i < message.comment.length; ++i) + if ( + !$util.isInteger(message.comment[i]) && + !( + message.comment[i] && + $util.isInteger(message.comment[i].low) && + $util.isInteger(message.comment[i].high) + ) + ) + return 'comment: integer|Long[] expected' + } + if (message.defaultSampleType != null && message.hasOwnProperty('defaultSampleType')) + if ( + !$util.isInteger(message.defaultSampleType) && + !( + message.defaultSampleType && + $util.isInteger(message.defaultSampleType.low) && + $util.isInteger(message.defaultSampleType.high) + ) + ) + return 'defaultSampleType: integer|Long expected' + return null + } + + /** + * Creates a Profile message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Profile + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Profile} Profile + */ + Profile.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Profile) return object + var message = new $root.perftools.profiles.Profile() + if (object.sampleType) { + if (!Array.isArray(object.sampleType)) + throw TypeError('.perftools.profiles.Profile.sampleType: array expected') + message.sampleType = [] + for (var i = 0; i < object.sampleType.length; ++i) { + if (typeof object.sampleType[i] !== 'object') + throw TypeError('.perftools.profiles.Profile.sampleType: object expected') + message.sampleType[i] = $root.perftools.profiles.ValueType.fromObject( + object.sampleType[i], + ) + } + } + if (object.sample) { + if (!Array.isArray(object.sample)) + throw TypeError('.perftools.profiles.Profile.sample: array expected') + message.sample = [] + for (var i = 0; i < object.sample.length; ++i) { + if (typeof object.sample[i] !== 'object') + throw TypeError('.perftools.profiles.Profile.sample: object expected') + message.sample[i] = $root.perftools.profiles.Sample.fromObject(object.sample[i]) + } + } + if (object.mapping) { + if (!Array.isArray(object.mapping)) + throw TypeError('.perftools.profiles.Profile.mapping: array expected') + message.mapping = [] + for (var i = 0; i < object.mapping.length; ++i) { + if (typeof object.mapping[i] !== 'object') + throw TypeError('.perftools.profiles.Profile.mapping: object expected') + message.mapping[i] = $root.perftools.profiles.Mapping.fromObject(object.mapping[i]) + } + } + if (object.location) { + if (!Array.isArray(object.location)) + throw TypeError('.perftools.profiles.Profile.location: array expected') + message.location = [] + for (var i = 0; i < object.location.length; ++i) { + if (typeof object.location[i] !== 'object') + throw TypeError('.perftools.profiles.Profile.location: object expected') + message.location[i] = $root.perftools.profiles.Location.fromObject(object.location[i]) + } + } + if (object['function']) { + if (!Array.isArray(object['function'])) + throw TypeError('.perftools.profiles.Profile.function: array expected') + message['function'] = [] + for (var i = 0; i < object['function'].length; ++i) { + if (typeof object['function'][i] !== 'object') + throw TypeError('.perftools.profiles.Profile.function: object expected') + message['function'][i] = $root.perftools.profiles.Function.fromObject( + object['function'][i], + ) + } + } + if (object.stringTable) { + if (!Array.isArray(object.stringTable)) + throw TypeError('.perftools.profiles.Profile.stringTable: array expected') + message.stringTable = [] + for (var i = 0; i < object.stringTable.length; ++i) + message.stringTable[i] = String(object.stringTable[i]) + } + if (object.dropFrames != null) + if ($util.Long) + (message.dropFrames = $util.Long.fromValue(object.dropFrames)).unsigned = false + else if (typeof object.dropFrames === 'string') + message.dropFrames = parseInt(object.dropFrames, 10) + else if (typeof object.dropFrames === 'number') message.dropFrames = object.dropFrames + else if (typeof object.dropFrames === 'object') + message.dropFrames = new $util.LongBits( + object.dropFrames.low >>> 0, + object.dropFrames.high >>> 0, + ).toNumber() + if (object.keepFrames != null) + if ($util.Long) + (message.keepFrames = $util.Long.fromValue(object.keepFrames)).unsigned = false + else if (typeof object.keepFrames === 'string') + message.keepFrames = parseInt(object.keepFrames, 10) + else if (typeof object.keepFrames === 'number') message.keepFrames = object.keepFrames + else if (typeof object.keepFrames === 'object') + message.keepFrames = new $util.LongBits( + object.keepFrames.low >>> 0, + object.keepFrames.high >>> 0, + ).toNumber() + if (object.timeNanos != null) + if ($util.Long) + (message.timeNanos = $util.Long.fromValue(object.timeNanos)).unsigned = false + else if (typeof object.timeNanos === 'string') + message.timeNanos = parseInt(object.timeNanos, 10) + else if (typeof object.timeNanos === 'number') message.timeNanos = object.timeNanos + else if (typeof object.timeNanos === 'object') + message.timeNanos = new $util.LongBits( + object.timeNanos.low >>> 0, + object.timeNanos.high >>> 0, + ).toNumber() + if (object.durationNanos != null) + if ($util.Long) + (message.durationNanos = $util.Long.fromValue(object.durationNanos)).unsigned = false + else if (typeof object.durationNanos === 'string') + message.durationNanos = parseInt(object.durationNanos, 10) + else if (typeof object.durationNanos === 'number') + message.durationNanos = object.durationNanos + else if (typeof object.durationNanos === 'object') + message.durationNanos = new $util.LongBits( + object.durationNanos.low >>> 0, + object.durationNanos.high >>> 0, + ).toNumber() + if (object.periodType != null) { + if (typeof object.periodType !== 'object') + throw TypeError('.perftools.profiles.Profile.periodType: object expected') + message.periodType = $root.perftools.profiles.ValueType.fromObject(object.periodType) + } + if (object.period != null) + if ($util.Long) (message.period = $util.Long.fromValue(object.period)).unsigned = false + else if (typeof object.period === 'string') message.period = parseInt(object.period, 10) + else if (typeof object.period === 'number') message.period = object.period + else if (typeof object.period === 'object') + message.period = new $util.LongBits( + object.period.low >>> 0, + object.period.high >>> 0, + ).toNumber() + if (object.comment) { + if (!Array.isArray(object.comment)) + throw TypeError('.perftools.profiles.Profile.comment: array expected') + message.comment = [] + for (var i = 0; i < object.comment.length; ++i) + if ($util.Long) + (message.comment[i] = $util.Long.fromValue(object.comment[i])).unsigned = false + else if (typeof object.comment[i] === 'string') + message.comment[i] = parseInt(object.comment[i], 10) + else if (typeof object.comment[i] === 'number') message.comment[i] = object.comment[i] + else if (typeof object.comment[i] === 'object') + message.comment[i] = new $util.LongBits( + object.comment[i].low >>> 0, + object.comment[i].high >>> 0, + ).toNumber() + } + if (object.defaultSampleType != null) + if ($util.Long) + (message.defaultSampleType = $util.Long.fromValue( + object.defaultSampleType, + )).unsigned = false + else if (typeof object.defaultSampleType === 'string') + message.defaultSampleType = parseInt(object.defaultSampleType, 10) + else if (typeof object.defaultSampleType === 'number') + message.defaultSampleType = object.defaultSampleType + else if (typeof object.defaultSampleType === 'object') + message.defaultSampleType = new $util.LongBits( + object.defaultSampleType.low >>> 0, + object.defaultSampleType.high >>> 0, + ).toNumber() + return message + } + + /** + * Creates a plain object from a Profile message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Profile + * @static + * @param {perftools.profiles.Profile} message Profile + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Profile.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.arrays || options.defaults) { + object.sampleType = [] + object.sample = [] + object.mapping = [] + object.location = [] + object['function'] = [] + object.stringTable = [] + object.comment = [] + } + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.dropFrames = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.dropFrames = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.keepFrames = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.keepFrames = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.timeNanos = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.timeNanos = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.durationNanos = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.durationNanos = options.longs === String ? '0' : 0 + object.periodType = null + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.period = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.period = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.defaultSampleType = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.defaultSampleType = options.longs === String ? '0' : 0 + } + if (message.sampleType && message.sampleType.length) { + object.sampleType = [] + for (var j = 0; j < message.sampleType.length; ++j) + object.sampleType[j] = $root.perftools.profiles.ValueType.toObject( + message.sampleType[j], + options, + ) + } + if (message.sample && message.sample.length) { + object.sample = [] + for (var j = 0; j < message.sample.length; ++j) + object.sample[j] = $root.perftools.profiles.Sample.toObject(message.sample[j], options) + } + if (message.mapping && message.mapping.length) { + object.mapping = [] + for (var j = 0; j < message.mapping.length; ++j) + object.mapping[j] = $root.perftools.profiles.Mapping.toObject( + message.mapping[j], + options, + ) + } + if (message.location && message.location.length) { + object.location = [] + for (var j = 0; j < message.location.length; ++j) + object.location[j] = $root.perftools.profiles.Location.toObject( + message.location[j], + options, + ) + } + if (message['function'] && message['function'].length) { + object['function'] = [] + for (var j = 0; j < message['function'].length; ++j) + object['function'][j] = $root.perftools.profiles.Function.toObject( + message['function'][j], + options, + ) + } + if (message.stringTable && message.stringTable.length) { + object.stringTable = [] + for (var j = 0; j < message.stringTable.length; ++j) + object.stringTable[j] = message.stringTable[j] + } + if (message.dropFrames != null && message.hasOwnProperty('dropFrames')) + if (typeof message.dropFrames === 'number') + object.dropFrames = + options.longs === String ? String(message.dropFrames) : message.dropFrames + else + object.dropFrames = + options.longs === String + ? $util.Long.prototype.toString.call(message.dropFrames) + : options.longs === Number + ? new $util.LongBits( + message.dropFrames.low >>> 0, + message.dropFrames.high >>> 0, + ).toNumber() + : message.dropFrames + if (message.keepFrames != null && message.hasOwnProperty('keepFrames')) + if (typeof message.keepFrames === 'number') + object.keepFrames = + options.longs === String ? String(message.keepFrames) : message.keepFrames + else + object.keepFrames = + options.longs === String + ? $util.Long.prototype.toString.call(message.keepFrames) + : options.longs === Number + ? new $util.LongBits( + message.keepFrames.low >>> 0, + message.keepFrames.high >>> 0, + ).toNumber() + : message.keepFrames + if (message.timeNanos != null && message.hasOwnProperty('timeNanos')) + if (typeof message.timeNanos === 'number') + object.timeNanos = + options.longs === String ? String(message.timeNanos) : message.timeNanos + else + object.timeNanos = + options.longs === String + ? $util.Long.prototype.toString.call(message.timeNanos) + : options.longs === Number + ? new $util.LongBits( + message.timeNanos.low >>> 0, + message.timeNanos.high >>> 0, + ).toNumber() + : message.timeNanos + if (message.durationNanos != null && message.hasOwnProperty('durationNanos')) + if (typeof message.durationNanos === 'number') + object.durationNanos = + options.longs === String ? String(message.durationNanos) : message.durationNanos + else + object.durationNanos = + options.longs === String + ? $util.Long.prototype.toString.call(message.durationNanos) + : options.longs === Number + ? new $util.LongBits( + message.durationNanos.low >>> 0, + message.durationNanos.high >>> 0, + ).toNumber() + : message.durationNanos + if (message.periodType != null && message.hasOwnProperty('periodType')) + object.periodType = $root.perftools.profiles.ValueType.toObject( + message.periodType, + options, + ) + if (message.period != null && message.hasOwnProperty('period')) + if (typeof message.period === 'number') + object.period = options.longs === String ? String(message.period) : message.period + else + object.period = + options.longs === String + ? $util.Long.prototype.toString.call(message.period) + : options.longs === Number + ? new $util.LongBits( + message.period.low >>> 0, + message.period.high >>> 0, + ).toNumber() + : message.period + if (message.comment && message.comment.length) { + object.comment = [] + for (var j = 0; j < message.comment.length; ++j) + if (typeof message.comment[j] === 'number') + object.comment[j] = + options.longs === String ? String(message.comment[j]) : message.comment[j] + else + object.comment[j] = + options.longs === String + ? $util.Long.prototype.toString.call(message.comment[j]) + : options.longs === Number + ? new $util.LongBits( + message.comment[j].low >>> 0, + message.comment[j].high >>> 0, + ).toNumber() + : message.comment[j] + } + if (message.defaultSampleType != null && message.hasOwnProperty('defaultSampleType')) + if (typeof message.defaultSampleType === 'number') + object.defaultSampleType = + options.longs === String + ? String(message.defaultSampleType) + : message.defaultSampleType + else + object.defaultSampleType = + options.longs === String + ? $util.Long.prototype.toString.call(message.defaultSampleType) + : options.longs === Number + ? new $util.LongBits( + message.defaultSampleType.low >>> 0, + message.defaultSampleType.high >>> 0, + ).toNumber() + : message.defaultSampleType + return object + } + + /** + * Converts this Profile to JSON. + * @function toJSON + * @memberof perftools.profiles.Profile + * @instance + * @returns {Object.} JSON object + */ + Profile.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Profile + })() + + profiles.ValueType = (function() { + /** + * Properties of a ValueType. + * @memberof perftools.profiles + * @interface IValueType + * @property {number|Long|null} [type] ValueType type + * @property {number|Long|null} [unit] ValueType unit + */ + + /** + * Constructs a new ValueType. + * @memberof perftools.profiles + * @classdesc Represents a ValueType. + * @implements IValueType + * @constructor + * @param {perftools.profiles.IValueType=} [properties] Properties to set + */ + function ValueType(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * ValueType type. + * @member {number|Long} type + * @memberof perftools.profiles.ValueType + * @instance + */ + ValueType.prototype.type = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * ValueType unit. + * @member {number|Long} unit + * @memberof perftools.profiles.ValueType + * @instance + */ + ValueType.prototype.unit = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Creates a new ValueType instance using the specified properties. + * @function create + * @memberof perftools.profiles.ValueType + * @static + * @param {perftools.profiles.IValueType=} [properties] Properties to set + * @returns {perftools.profiles.ValueType} ValueType instance + */ + ValueType.create = function create(properties) { + return new ValueType(properties) + } + + /** + * Encodes the specified ValueType message. Does not implicitly {@link perftools.profiles.ValueType.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.ValueType + * @static + * @param {perftools.profiles.IValueType} message ValueType message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ValueType.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.type != null && message.hasOwnProperty('type')) + writer.uint32(/* id 1, wireType 0 =*/ 8).int64(message.type) + if (message.unit != null && message.hasOwnProperty('unit')) + writer.uint32(/* id 2, wireType 0 =*/ 16).int64(message.unit) + return writer + } + + /** + * Encodes the specified ValueType message, length delimited. Does not implicitly {@link perftools.profiles.ValueType.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.ValueType + * @static + * @param {perftools.profiles.IValueType} message ValueType message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ValueType.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a ValueType message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.ValueType + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.ValueType} ValueType + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ValueType.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.ValueType() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.type = reader.int64() + break + case 2: + message.unit = reader.int64() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a ValueType message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.ValueType + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.ValueType} ValueType + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ValueType.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a ValueType message. + * @function verify + * @memberof perftools.profiles.ValueType + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ValueType.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.type != null && message.hasOwnProperty('type')) + if ( + !$util.isInteger(message.type) && + !( + message.type && + $util.isInteger(message.type.low) && + $util.isInteger(message.type.high) + ) + ) + return 'type: integer|Long expected' + if (message.unit != null && message.hasOwnProperty('unit')) + if ( + !$util.isInteger(message.unit) && + !( + message.unit && + $util.isInteger(message.unit.low) && + $util.isInteger(message.unit.high) + ) + ) + return 'unit: integer|Long expected' + return null + } + + /** + * Creates a ValueType message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.ValueType + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.ValueType} ValueType + */ + ValueType.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.ValueType) return object + var message = new $root.perftools.profiles.ValueType() + if (object.type != null) + if ($util.Long) (message.type = $util.Long.fromValue(object.type)).unsigned = false + else if (typeof object.type === 'string') message.type = parseInt(object.type, 10) + else if (typeof object.type === 'number') message.type = object.type + else if (typeof object.type === 'object') + message.type = new $util.LongBits( + object.type.low >>> 0, + object.type.high >>> 0, + ).toNumber() + if (object.unit != null) + if ($util.Long) (message.unit = $util.Long.fromValue(object.unit)).unsigned = false + else if (typeof object.unit === 'string') message.unit = parseInt(object.unit, 10) + else if (typeof object.unit === 'number') message.unit = object.unit + else if (typeof object.unit === 'object') + message.unit = new $util.LongBits( + object.unit.low >>> 0, + object.unit.high >>> 0, + ).toNumber() + return message + } + + /** + * Creates a plain object from a ValueType message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.ValueType + * @static + * @param {perftools.profiles.ValueType} message ValueType + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ValueType.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.type = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.type = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.unit = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.unit = options.longs === String ? '0' : 0 + } + if (message.type != null && message.hasOwnProperty('type')) + if (typeof message.type === 'number') + object.type = options.longs === String ? String(message.type) : message.type + else + object.type = + options.longs === String + ? $util.Long.prototype.toString.call(message.type) + : options.longs === Number + ? new $util.LongBits(message.type.low >>> 0, message.type.high >>> 0).toNumber() + : message.type + if (message.unit != null && message.hasOwnProperty('unit')) + if (typeof message.unit === 'number') + object.unit = options.longs === String ? String(message.unit) : message.unit + else + object.unit = + options.longs === String + ? $util.Long.prototype.toString.call(message.unit) + : options.longs === Number + ? new $util.LongBits(message.unit.low >>> 0, message.unit.high >>> 0).toNumber() + : message.unit + return object + } + + /** + * Converts this ValueType to JSON. + * @function toJSON + * @memberof perftools.profiles.ValueType + * @instance + * @returns {Object.} JSON object + */ + ValueType.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return ValueType + })() + + profiles.Sample = (function() { + /** + * Properties of a Sample. + * @memberof perftools.profiles + * @interface ISample + * @property {Array.|null} [locationId] Sample locationId + * @property {Array.|null} [value] Sample value + * @property {Array.|null} [label] Sample label + */ + + /** + * Constructs a new Sample. + * @memberof perftools.profiles + * @classdesc Represents a Sample. + * @implements ISample + * @constructor + * @param {perftools.profiles.ISample=} [properties] Properties to set + */ + function Sample(properties) { + this.locationId = [] + this.value = [] + this.label = [] + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Sample locationId. + * @member {Array.} locationId + * @memberof perftools.profiles.Sample + * @instance + */ + Sample.prototype.locationId = $util.emptyArray + + /** + * Sample value. + * @member {Array.} value + * @memberof perftools.profiles.Sample + * @instance + */ + Sample.prototype.value = $util.emptyArray + + /** + * Sample label. + * @member {Array.} label + * @memberof perftools.profiles.Sample + * @instance + */ + Sample.prototype.label = $util.emptyArray + + /** + * Creates a new Sample instance using the specified properties. + * @function create + * @memberof perftools.profiles.Sample + * @static + * @param {perftools.profiles.ISample=} [properties] Properties to set + * @returns {perftools.profiles.Sample} Sample instance + */ + Sample.create = function create(properties) { + return new Sample(properties) + } + + /** + * Encodes the specified Sample message. Does not implicitly {@link perftools.profiles.Sample.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Sample + * @static + * @param {perftools.profiles.ISample} message Sample message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Sample.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.locationId != null && message.locationId.length) { + writer.uint32(/* id 1, wireType 2 =*/ 10).fork() + for (var i = 0; i < message.locationId.length; ++i) writer.uint64(message.locationId[i]) + writer.ldelim() + } + if (message.value != null && message.value.length) { + writer.uint32(/* id 2, wireType 2 =*/ 18).fork() + for (var i = 0; i < message.value.length; ++i) writer.int64(message.value[i]) + writer.ldelim() + } + if (message.label != null && message.label.length) + for (var i = 0; i < message.label.length; ++i) + $root.perftools.profiles.Label.encode( + message.label[i], + writer.uint32(/* id 3, wireType 2 =*/ 26).fork(), + ).ldelim() + return writer + } + + /** + * Encodes the specified Sample message, length delimited. Does not implicitly {@link perftools.profiles.Sample.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Sample + * @static + * @param {perftools.profiles.ISample} message Sample message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Sample.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Sample message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Sample + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Sample} Sample + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Sample.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Sample() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + if (!(message.locationId && message.locationId.length)) message.locationId = [] + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos + while (reader.pos < end2) message.locationId.push(reader.uint64()) + } else message.locationId.push(reader.uint64()) + break + case 2: + if (!(message.value && message.value.length)) message.value = [] + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos + while (reader.pos < end2) message.value.push(reader.int64()) + } else message.value.push(reader.int64()) + break + case 3: + if (!(message.label && message.label.length)) message.label = [] + message.label.push($root.perftools.profiles.Label.decode(reader, reader.uint32())) + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Sample message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Sample + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Sample} Sample + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Sample.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Sample message. + * @function verify + * @memberof perftools.profiles.Sample + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Sample.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.locationId != null && message.hasOwnProperty('locationId')) { + if (!Array.isArray(message.locationId)) return 'locationId: array expected' + for (var i = 0; i < message.locationId.length; ++i) + if ( + !$util.isInteger(message.locationId[i]) && + !( + message.locationId[i] && + $util.isInteger(message.locationId[i].low) && + $util.isInteger(message.locationId[i].high) + ) + ) + return 'locationId: integer|Long[] expected' + } + if (message.value != null && message.hasOwnProperty('value')) { + if (!Array.isArray(message.value)) return 'value: array expected' + for (var i = 0; i < message.value.length; ++i) + if ( + !$util.isInteger(message.value[i]) && + !( + message.value[i] && + $util.isInteger(message.value[i].low) && + $util.isInteger(message.value[i].high) + ) + ) + return 'value: integer|Long[] expected' + } + if (message.label != null && message.hasOwnProperty('label')) { + if (!Array.isArray(message.label)) return 'label: array expected' + for (var i = 0; i < message.label.length; ++i) { + var error = $root.perftools.profiles.Label.verify(message.label[i]) + if (error) return 'label.' + error + } + } + return null + } + + /** + * Creates a Sample message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Sample + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Sample} Sample + */ + Sample.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Sample) return object + var message = new $root.perftools.profiles.Sample() + if (object.locationId) { + if (!Array.isArray(object.locationId)) + throw TypeError('.perftools.profiles.Sample.locationId: array expected') + message.locationId = [] + for (var i = 0; i < object.locationId.length; ++i) + if ($util.Long) + (message.locationId[i] = $util.Long.fromValue(object.locationId[i])).unsigned = true + else if (typeof object.locationId[i] === 'string') + message.locationId[i] = parseInt(object.locationId[i], 10) + else if (typeof object.locationId[i] === 'number') + message.locationId[i] = object.locationId[i] + else if (typeof object.locationId[i] === 'object') + message.locationId[i] = new $util.LongBits( + object.locationId[i].low >>> 0, + object.locationId[i].high >>> 0, + ).toNumber(true) + } + if (object.value) { + if (!Array.isArray(object.value)) + throw TypeError('.perftools.profiles.Sample.value: array expected') + message.value = [] + for (var i = 0; i < object.value.length; ++i) + if ($util.Long) + (message.value[i] = $util.Long.fromValue(object.value[i])).unsigned = false + else if (typeof object.value[i] === 'string') + message.value[i] = parseInt(object.value[i], 10) + else if (typeof object.value[i] === 'number') message.value[i] = object.value[i] + else if (typeof object.value[i] === 'object') + message.value[i] = new $util.LongBits( + object.value[i].low >>> 0, + object.value[i].high >>> 0, + ).toNumber() + } + if (object.label) { + if (!Array.isArray(object.label)) + throw TypeError('.perftools.profiles.Sample.label: array expected') + message.label = [] + for (var i = 0; i < object.label.length; ++i) { + if (typeof object.label[i] !== 'object') + throw TypeError('.perftools.profiles.Sample.label: object expected') + message.label[i] = $root.perftools.profiles.Label.fromObject(object.label[i]) + } + } + return message + } + + /** + * Creates a plain object from a Sample message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Sample + * @static + * @param {perftools.profiles.Sample} message Sample + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Sample.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.arrays || options.defaults) { + object.locationId = [] + object.value = [] + object.label = [] + } + if (message.locationId && message.locationId.length) { + object.locationId = [] + for (var j = 0; j < message.locationId.length; ++j) + if (typeof message.locationId[j] === 'number') + object.locationId[j] = + options.longs === String ? String(message.locationId[j]) : message.locationId[j] + else + object.locationId[j] = + options.longs === String + ? $util.Long.prototype.toString.call(message.locationId[j]) + : options.longs === Number + ? new $util.LongBits( + message.locationId[j].low >>> 0, + message.locationId[j].high >>> 0, + ).toNumber(true) + : message.locationId[j] + } + if (message.value && message.value.length) { + object.value = [] + for (var j = 0; j < message.value.length; ++j) + if (typeof message.value[j] === 'number') + object.value[j] = + options.longs === String ? String(message.value[j]) : message.value[j] + else + object.value[j] = + options.longs === String + ? $util.Long.prototype.toString.call(message.value[j]) + : options.longs === Number + ? new $util.LongBits( + message.value[j].low >>> 0, + message.value[j].high >>> 0, + ).toNumber() + : message.value[j] + } + if (message.label && message.label.length) { + object.label = [] + for (var j = 0; j < message.label.length; ++j) + object.label[j] = $root.perftools.profiles.Label.toObject(message.label[j], options) + } + return object + } + + /** + * Converts this Sample to JSON. + * @function toJSON + * @memberof perftools.profiles.Sample + * @instance + * @returns {Object.} JSON object + */ + Sample.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Sample + })() + + profiles.Label = (function() { + /** + * Properties of a Label. + * @memberof perftools.profiles + * @interface ILabel + * @property {number|Long|null} [key] Label key + * @property {number|Long|null} [str] Label str + * @property {number|Long|null} [num] Label num + * @property {number|Long|null} [numUnit] Label numUnit + */ + + /** + * Constructs a new Label. + * @memberof perftools.profiles + * @classdesc Represents a Label. + * @implements ILabel + * @constructor + * @param {perftools.profiles.ILabel=} [properties] Properties to set + */ + function Label(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Label key. + * @member {number|Long} key + * @memberof perftools.profiles.Label + * @instance + */ + Label.prototype.key = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Label str. + * @member {number|Long} str + * @memberof perftools.profiles.Label + * @instance + */ + Label.prototype.str = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Label num. + * @member {number|Long} num + * @memberof perftools.profiles.Label + * @instance + */ + Label.prototype.num = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Label numUnit. + * @member {number|Long} numUnit + * @memberof perftools.profiles.Label + * @instance + */ + Label.prototype.numUnit = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Creates a new Label instance using the specified properties. + * @function create + * @memberof perftools.profiles.Label + * @static + * @param {perftools.profiles.ILabel=} [properties] Properties to set + * @returns {perftools.profiles.Label} Label instance + */ + Label.create = function create(properties) { + return new Label(properties) + } + + /** + * Encodes the specified Label message. Does not implicitly {@link perftools.profiles.Label.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Label + * @static + * @param {perftools.profiles.ILabel} message Label message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Label.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.key != null && message.hasOwnProperty('key')) + writer.uint32(/* id 1, wireType 0 =*/ 8).int64(message.key) + if (message.str != null && message.hasOwnProperty('str')) + writer.uint32(/* id 2, wireType 0 =*/ 16).int64(message.str) + if (message.num != null && message.hasOwnProperty('num')) + writer.uint32(/* id 3, wireType 0 =*/ 24).int64(message.num) + if (message.numUnit != null && message.hasOwnProperty('numUnit')) + writer.uint32(/* id 4, wireType 0 =*/ 32).int64(message.numUnit) + return writer + } + + /** + * Encodes the specified Label message, length delimited. Does not implicitly {@link perftools.profiles.Label.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Label + * @static + * @param {perftools.profiles.ILabel} message Label message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Label.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Label message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Label + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Label} Label + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Label.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Label() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.key = reader.int64() + break + case 2: + message.str = reader.int64() + break + case 3: + message.num = reader.int64() + break + case 4: + message.numUnit = reader.int64() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Label message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Label + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Label} Label + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Label.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Label message. + * @function verify + * @memberof perftools.profiles.Label + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Label.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.key != null && message.hasOwnProperty('key')) + if ( + !$util.isInteger(message.key) && + !(message.key && $util.isInteger(message.key.low) && $util.isInteger(message.key.high)) + ) + return 'key: integer|Long expected' + if (message.str != null && message.hasOwnProperty('str')) + if ( + !$util.isInteger(message.str) && + !(message.str && $util.isInteger(message.str.low) && $util.isInteger(message.str.high)) + ) + return 'str: integer|Long expected' + if (message.num != null && message.hasOwnProperty('num')) + if ( + !$util.isInteger(message.num) && + !(message.num && $util.isInteger(message.num.low) && $util.isInteger(message.num.high)) + ) + return 'num: integer|Long expected' + if (message.numUnit != null && message.hasOwnProperty('numUnit')) + if ( + !$util.isInteger(message.numUnit) && + !( + message.numUnit && + $util.isInteger(message.numUnit.low) && + $util.isInteger(message.numUnit.high) + ) + ) + return 'numUnit: integer|Long expected' + return null + } + + /** + * Creates a Label message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Label + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Label} Label + */ + Label.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Label) return object + var message = new $root.perftools.profiles.Label() + if (object.key != null) + if ($util.Long) (message.key = $util.Long.fromValue(object.key)).unsigned = false + else if (typeof object.key === 'string') message.key = parseInt(object.key, 10) + else if (typeof object.key === 'number') message.key = object.key + else if (typeof object.key === 'object') + message.key = new $util.LongBits(object.key.low >>> 0, object.key.high >>> 0).toNumber() + if (object.str != null) + if ($util.Long) (message.str = $util.Long.fromValue(object.str)).unsigned = false + else if (typeof object.str === 'string') message.str = parseInt(object.str, 10) + else if (typeof object.str === 'number') message.str = object.str + else if (typeof object.str === 'object') + message.str = new $util.LongBits(object.str.low >>> 0, object.str.high >>> 0).toNumber() + if (object.num != null) + if ($util.Long) (message.num = $util.Long.fromValue(object.num)).unsigned = false + else if (typeof object.num === 'string') message.num = parseInt(object.num, 10) + else if (typeof object.num === 'number') message.num = object.num + else if (typeof object.num === 'object') + message.num = new $util.LongBits(object.num.low >>> 0, object.num.high >>> 0).toNumber() + if (object.numUnit != null) + if ($util.Long) (message.numUnit = $util.Long.fromValue(object.numUnit)).unsigned = false + else if (typeof object.numUnit === 'string') + message.numUnit = parseInt(object.numUnit, 10) + else if (typeof object.numUnit === 'number') message.numUnit = object.numUnit + else if (typeof object.numUnit === 'object') + message.numUnit = new $util.LongBits( + object.numUnit.low >>> 0, + object.numUnit.high >>> 0, + ).toNumber() + return message + } + + /** + * Creates a plain object from a Label message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Label + * @static + * @param {perftools.profiles.Label} message Label + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Label.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.key = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.key = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.str = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.str = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.num = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.num = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.numUnit = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.numUnit = options.longs === String ? '0' : 0 + } + if (message.key != null && message.hasOwnProperty('key')) + if (typeof message.key === 'number') + object.key = options.longs === String ? String(message.key) : message.key + else + object.key = + options.longs === String + ? $util.Long.prototype.toString.call(message.key) + : options.longs === Number + ? new $util.LongBits(message.key.low >>> 0, message.key.high >>> 0).toNumber() + : message.key + if (message.str != null && message.hasOwnProperty('str')) + if (typeof message.str === 'number') + object.str = options.longs === String ? String(message.str) : message.str + else + object.str = + options.longs === String + ? $util.Long.prototype.toString.call(message.str) + : options.longs === Number + ? new $util.LongBits(message.str.low >>> 0, message.str.high >>> 0).toNumber() + : message.str + if (message.num != null && message.hasOwnProperty('num')) + if (typeof message.num === 'number') + object.num = options.longs === String ? String(message.num) : message.num + else + object.num = + options.longs === String + ? $util.Long.prototype.toString.call(message.num) + : options.longs === Number + ? new $util.LongBits(message.num.low >>> 0, message.num.high >>> 0).toNumber() + : message.num + if (message.numUnit != null && message.hasOwnProperty('numUnit')) + if (typeof message.numUnit === 'number') + object.numUnit = options.longs === String ? String(message.numUnit) : message.numUnit + else + object.numUnit = + options.longs === String + ? $util.Long.prototype.toString.call(message.numUnit) + : options.longs === Number + ? new $util.LongBits( + message.numUnit.low >>> 0, + message.numUnit.high >>> 0, + ).toNumber() + : message.numUnit + return object + } + + /** + * Converts this Label to JSON. + * @function toJSON + * @memberof perftools.profiles.Label + * @instance + * @returns {Object.} JSON object + */ + Label.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Label + })() + + profiles.Mapping = (function() { + /** + * Properties of a Mapping. + * @memberof perftools.profiles + * @interface IMapping + * @property {number|Long|null} [id] Mapping id + * @property {number|Long|null} [memoryStart] Mapping memoryStart + * @property {number|Long|null} [memoryLimit] Mapping memoryLimit + * @property {number|Long|null} [fileOffset] Mapping fileOffset + * @property {number|Long|null} [filename] Mapping filename + * @property {number|Long|null} [buildId] Mapping buildId + * @property {boolean|null} [hasFunctions] Mapping hasFunctions + * @property {boolean|null} [hasFilenames] Mapping hasFilenames + * @property {boolean|null} [hasLineNumbers] Mapping hasLineNumbers + * @property {boolean|null} [hasInlineFrames] Mapping hasInlineFrames + */ + + /** + * Constructs a new Mapping. + * @memberof perftools.profiles + * @classdesc Represents a Mapping. + * @implements IMapping + * @constructor + * @param {perftools.profiles.IMapping=} [properties] Properties to set + */ + function Mapping(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Mapping id. + * @member {number|Long} id + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.id = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Mapping memoryStart. + * @member {number|Long} memoryStart + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.memoryStart = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Mapping memoryLimit. + * @member {number|Long} memoryLimit + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.memoryLimit = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Mapping fileOffset. + * @member {number|Long} fileOffset + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.fileOffset = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Mapping filename. + * @member {number|Long} filename + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.filename = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Mapping buildId. + * @member {number|Long} buildId + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.buildId = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Mapping hasFunctions. + * @member {boolean} hasFunctions + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.hasFunctions = false + + /** + * Mapping hasFilenames. + * @member {boolean} hasFilenames + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.hasFilenames = false + + /** + * Mapping hasLineNumbers. + * @member {boolean} hasLineNumbers + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.hasLineNumbers = false + + /** + * Mapping hasInlineFrames. + * @member {boolean} hasInlineFrames + * @memberof perftools.profiles.Mapping + * @instance + */ + Mapping.prototype.hasInlineFrames = false + + /** + * Creates a new Mapping instance using the specified properties. + * @function create + * @memberof perftools.profiles.Mapping + * @static + * @param {perftools.profiles.IMapping=} [properties] Properties to set + * @returns {perftools.profiles.Mapping} Mapping instance + */ + Mapping.create = function create(properties) { + return new Mapping(properties) + } + + /** + * Encodes the specified Mapping message. Does not implicitly {@link perftools.profiles.Mapping.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Mapping + * @static + * @param {perftools.profiles.IMapping} message Mapping message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Mapping.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.id != null && message.hasOwnProperty('id')) + writer.uint32(/* id 1, wireType 0 =*/ 8).uint64(message.id) + if (message.memoryStart != null && message.hasOwnProperty('memoryStart')) + writer.uint32(/* id 2, wireType 0 =*/ 16).uint64(message.memoryStart) + if (message.memoryLimit != null && message.hasOwnProperty('memoryLimit')) + writer.uint32(/* id 3, wireType 0 =*/ 24).uint64(message.memoryLimit) + if (message.fileOffset != null && message.hasOwnProperty('fileOffset')) + writer.uint32(/* id 4, wireType 0 =*/ 32).uint64(message.fileOffset) + if (message.filename != null && message.hasOwnProperty('filename')) + writer.uint32(/* id 5, wireType 0 =*/ 40).int64(message.filename) + if (message.buildId != null && message.hasOwnProperty('buildId')) + writer.uint32(/* id 6, wireType 0 =*/ 48).int64(message.buildId) + if (message.hasFunctions != null && message.hasOwnProperty('hasFunctions')) + writer.uint32(/* id 7, wireType 0 =*/ 56).bool(message.hasFunctions) + if (message.hasFilenames != null && message.hasOwnProperty('hasFilenames')) + writer.uint32(/* id 8, wireType 0 =*/ 64).bool(message.hasFilenames) + if (message.hasLineNumbers != null && message.hasOwnProperty('hasLineNumbers')) + writer.uint32(/* id 9, wireType 0 =*/ 72).bool(message.hasLineNumbers) + if (message.hasInlineFrames != null && message.hasOwnProperty('hasInlineFrames')) + writer.uint32(/* id 10, wireType 0 =*/ 80).bool(message.hasInlineFrames) + return writer + } + + /** + * Encodes the specified Mapping message, length delimited. Does not implicitly {@link perftools.profiles.Mapping.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Mapping + * @static + * @param {perftools.profiles.IMapping} message Mapping message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Mapping.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Mapping message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Mapping + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Mapping} Mapping + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Mapping.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Mapping() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.id = reader.uint64() + break + case 2: + message.memoryStart = reader.uint64() + break + case 3: + message.memoryLimit = reader.uint64() + break + case 4: + message.fileOffset = reader.uint64() + break + case 5: + message.filename = reader.int64() + break + case 6: + message.buildId = reader.int64() + break + case 7: + message.hasFunctions = reader.bool() + break + case 8: + message.hasFilenames = reader.bool() + break + case 9: + message.hasLineNumbers = reader.bool() + break + case 10: + message.hasInlineFrames = reader.bool() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Mapping message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Mapping + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Mapping} Mapping + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Mapping.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Mapping message. + * @function verify + * @memberof perftools.profiles.Mapping + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Mapping.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.id != null && message.hasOwnProperty('id')) + if ( + !$util.isInteger(message.id) && + !(message.id && $util.isInteger(message.id.low) && $util.isInteger(message.id.high)) + ) + return 'id: integer|Long expected' + if (message.memoryStart != null && message.hasOwnProperty('memoryStart')) + if ( + !$util.isInteger(message.memoryStart) && + !( + message.memoryStart && + $util.isInteger(message.memoryStart.low) && + $util.isInteger(message.memoryStart.high) + ) + ) + return 'memoryStart: integer|Long expected' + if (message.memoryLimit != null && message.hasOwnProperty('memoryLimit')) + if ( + !$util.isInteger(message.memoryLimit) && + !( + message.memoryLimit && + $util.isInteger(message.memoryLimit.low) && + $util.isInteger(message.memoryLimit.high) + ) + ) + return 'memoryLimit: integer|Long expected' + if (message.fileOffset != null && message.hasOwnProperty('fileOffset')) + if ( + !$util.isInteger(message.fileOffset) && + !( + message.fileOffset && + $util.isInteger(message.fileOffset.low) && + $util.isInteger(message.fileOffset.high) + ) + ) + return 'fileOffset: integer|Long expected' + if (message.filename != null && message.hasOwnProperty('filename')) + if ( + !$util.isInteger(message.filename) && + !( + message.filename && + $util.isInteger(message.filename.low) && + $util.isInteger(message.filename.high) + ) + ) + return 'filename: integer|Long expected' + if (message.buildId != null && message.hasOwnProperty('buildId')) + if ( + !$util.isInteger(message.buildId) && + !( + message.buildId && + $util.isInteger(message.buildId.low) && + $util.isInteger(message.buildId.high) + ) + ) + return 'buildId: integer|Long expected' + if (message.hasFunctions != null && message.hasOwnProperty('hasFunctions')) + if (typeof message.hasFunctions !== 'boolean') return 'hasFunctions: boolean expected' + if (message.hasFilenames != null && message.hasOwnProperty('hasFilenames')) + if (typeof message.hasFilenames !== 'boolean') return 'hasFilenames: boolean expected' + if (message.hasLineNumbers != null && message.hasOwnProperty('hasLineNumbers')) + if (typeof message.hasLineNumbers !== 'boolean') return 'hasLineNumbers: boolean expected' + if (message.hasInlineFrames != null && message.hasOwnProperty('hasInlineFrames')) + if (typeof message.hasInlineFrames !== 'boolean') + return 'hasInlineFrames: boolean expected' + return null + } + + /** + * Creates a Mapping message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Mapping + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Mapping} Mapping + */ + Mapping.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Mapping) return object + var message = new $root.perftools.profiles.Mapping() + if (object.id != null) + if ($util.Long) (message.id = $util.Long.fromValue(object.id)).unsigned = true + else if (typeof object.id === 'string') message.id = parseInt(object.id, 10) + else if (typeof object.id === 'number') message.id = object.id + else if (typeof object.id === 'object') + message.id = new $util.LongBits(object.id.low >>> 0, object.id.high >>> 0).toNumber( + true, + ) + if (object.memoryStart != null) + if ($util.Long) + (message.memoryStart = $util.Long.fromValue(object.memoryStart)).unsigned = true + else if (typeof object.memoryStart === 'string') + message.memoryStart = parseInt(object.memoryStart, 10) + else if (typeof object.memoryStart === 'number') message.memoryStart = object.memoryStart + else if (typeof object.memoryStart === 'object') + message.memoryStart = new $util.LongBits( + object.memoryStart.low >>> 0, + object.memoryStart.high >>> 0, + ).toNumber(true) + if (object.memoryLimit != null) + if ($util.Long) + (message.memoryLimit = $util.Long.fromValue(object.memoryLimit)).unsigned = true + else if (typeof object.memoryLimit === 'string') + message.memoryLimit = parseInt(object.memoryLimit, 10) + else if (typeof object.memoryLimit === 'number') message.memoryLimit = object.memoryLimit + else if (typeof object.memoryLimit === 'object') + message.memoryLimit = new $util.LongBits( + object.memoryLimit.low >>> 0, + object.memoryLimit.high >>> 0, + ).toNumber(true) + if (object.fileOffset != null) + if ($util.Long) + (message.fileOffset = $util.Long.fromValue(object.fileOffset)).unsigned = true + else if (typeof object.fileOffset === 'string') + message.fileOffset = parseInt(object.fileOffset, 10) + else if (typeof object.fileOffset === 'number') message.fileOffset = object.fileOffset + else if (typeof object.fileOffset === 'object') + message.fileOffset = new $util.LongBits( + object.fileOffset.low >>> 0, + object.fileOffset.high >>> 0, + ).toNumber(true) + if (object.filename != null) + if ($util.Long) + (message.filename = $util.Long.fromValue(object.filename)).unsigned = false + else if (typeof object.filename === 'string') + message.filename = parseInt(object.filename, 10) + else if (typeof object.filename === 'number') message.filename = object.filename + else if (typeof object.filename === 'object') + message.filename = new $util.LongBits( + object.filename.low >>> 0, + object.filename.high >>> 0, + ).toNumber() + if (object.buildId != null) + if ($util.Long) (message.buildId = $util.Long.fromValue(object.buildId)).unsigned = false + else if (typeof object.buildId === 'string') + message.buildId = parseInt(object.buildId, 10) + else if (typeof object.buildId === 'number') message.buildId = object.buildId + else if (typeof object.buildId === 'object') + message.buildId = new $util.LongBits( + object.buildId.low >>> 0, + object.buildId.high >>> 0, + ).toNumber() + if (object.hasFunctions != null) message.hasFunctions = Boolean(object.hasFunctions) + if (object.hasFilenames != null) message.hasFilenames = Boolean(object.hasFilenames) + if (object.hasLineNumbers != null) message.hasLineNumbers = Boolean(object.hasLineNumbers) + if (object.hasInlineFrames != null) + message.hasInlineFrames = Boolean(object.hasInlineFrames) + return message + } + + /** + * Creates a plain object from a Mapping message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Mapping + * @static + * @param {perftools.profiles.Mapping} message Mapping + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Mapping.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.id = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.id = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.memoryStart = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.memoryStart = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.memoryLimit = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.memoryLimit = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.fileOffset = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.fileOffset = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.filename = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.filename = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.buildId = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.buildId = options.longs === String ? '0' : 0 + object.hasFunctions = false + object.hasFilenames = false + object.hasLineNumbers = false + object.hasInlineFrames = false + } + if (message.id != null && message.hasOwnProperty('id')) + if (typeof message.id === 'number') + object.id = options.longs === String ? String(message.id) : message.id + else + object.id = + options.longs === String + ? $util.Long.prototype.toString.call(message.id) + : options.longs === Number + ? new $util.LongBits(message.id.low >>> 0, message.id.high >>> 0).toNumber(true) + : message.id + if (message.memoryStart != null && message.hasOwnProperty('memoryStart')) + if (typeof message.memoryStart === 'number') + object.memoryStart = + options.longs === String ? String(message.memoryStart) : message.memoryStart + else + object.memoryStart = + options.longs === String + ? $util.Long.prototype.toString.call(message.memoryStart) + : options.longs === Number + ? new $util.LongBits( + message.memoryStart.low >>> 0, + message.memoryStart.high >>> 0, + ).toNumber(true) + : message.memoryStart + if (message.memoryLimit != null && message.hasOwnProperty('memoryLimit')) + if (typeof message.memoryLimit === 'number') + object.memoryLimit = + options.longs === String ? String(message.memoryLimit) : message.memoryLimit + else + object.memoryLimit = + options.longs === String + ? $util.Long.prototype.toString.call(message.memoryLimit) + : options.longs === Number + ? new $util.LongBits( + message.memoryLimit.low >>> 0, + message.memoryLimit.high >>> 0, + ).toNumber(true) + : message.memoryLimit + if (message.fileOffset != null && message.hasOwnProperty('fileOffset')) + if (typeof message.fileOffset === 'number') + object.fileOffset = + options.longs === String ? String(message.fileOffset) : message.fileOffset + else + object.fileOffset = + options.longs === String + ? $util.Long.prototype.toString.call(message.fileOffset) + : options.longs === Number + ? new $util.LongBits( + message.fileOffset.low >>> 0, + message.fileOffset.high >>> 0, + ).toNumber(true) + : message.fileOffset + if (message.filename != null && message.hasOwnProperty('filename')) + if (typeof message.filename === 'number') + object.filename = options.longs === String ? String(message.filename) : message.filename + else + object.filename = + options.longs === String + ? $util.Long.prototype.toString.call(message.filename) + : options.longs === Number + ? new $util.LongBits( + message.filename.low >>> 0, + message.filename.high >>> 0, + ).toNumber() + : message.filename + if (message.buildId != null && message.hasOwnProperty('buildId')) + if (typeof message.buildId === 'number') + object.buildId = options.longs === String ? String(message.buildId) : message.buildId + else + object.buildId = + options.longs === String + ? $util.Long.prototype.toString.call(message.buildId) + : options.longs === Number + ? new $util.LongBits( + message.buildId.low >>> 0, + message.buildId.high >>> 0, + ).toNumber() + : message.buildId + if (message.hasFunctions != null && message.hasOwnProperty('hasFunctions')) + object.hasFunctions = message.hasFunctions + if (message.hasFilenames != null && message.hasOwnProperty('hasFilenames')) + object.hasFilenames = message.hasFilenames + if (message.hasLineNumbers != null && message.hasOwnProperty('hasLineNumbers')) + object.hasLineNumbers = message.hasLineNumbers + if (message.hasInlineFrames != null && message.hasOwnProperty('hasInlineFrames')) + object.hasInlineFrames = message.hasInlineFrames + return object + } + + /** + * Converts this Mapping to JSON. + * @function toJSON + * @memberof perftools.profiles.Mapping + * @instance + * @returns {Object.} JSON object + */ + Mapping.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Mapping + })() + + profiles.Location = (function() { + /** + * Properties of a Location. + * @memberof perftools.profiles + * @interface ILocation + * @property {number|Long|null} [id] Location id + * @property {number|Long|null} [mappingId] Location mappingId + * @property {number|Long|null} [address] Location address + * @property {Array.|null} [line] Location line + * @property {boolean|null} [isFolded] Location isFolded + */ + + /** + * Constructs a new Location. + * @memberof perftools.profiles + * @classdesc Represents a Location. + * @implements ILocation + * @constructor + * @param {perftools.profiles.ILocation=} [properties] Properties to set + */ + function Location(properties) { + this.line = [] + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Location id. + * @member {number|Long} id + * @memberof perftools.profiles.Location + * @instance + */ + Location.prototype.id = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Location mappingId. + * @member {number|Long} mappingId + * @memberof perftools.profiles.Location + * @instance + */ + Location.prototype.mappingId = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Location address. + * @member {number|Long} address + * @memberof perftools.profiles.Location + * @instance + */ + Location.prototype.address = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Location line. + * @member {Array.} line + * @memberof perftools.profiles.Location + * @instance + */ + Location.prototype.line = $util.emptyArray + + /** + * Location isFolded. + * @member {boolean} isFolded + * @memberof perftools.profiles.Location + * @instance + */ + Location.prototype.isFolded = false + + /** + * Creates a new Location instance using the specified properties. + * @function create + * @memberof perftools.profiles.Location + * @static + * @param {perftools.profiles.ILocation=} [properties] Properties to set + * @returns {perftools.profiles.Location} Location instance + */ + Location.create = function create(properties) { + return new Location(properties) + } + + /** + * Encodes the specified Location message. Does not implicitly {@link perftools.profiles.Location.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Location + * @static + * @param {perftools.profiles.ILocation} message Location message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Location.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.id != null && message.hasOwnProperty('id')) + writer.uint32(/* id 1, wireType 0 =*/ 8).uint64(message.id) + if (message.mappingId != null && message.hasOwnProperty('mappingId')) + writer.uint32(/* id 2, wireType 0 =*/ 16).uint64(message.mappingId) + if (message.address != null && message.hasOwnProperty('address')) + writer.uint32(/* id 3, wireType 0 =*/ 24).uint64(message.address) + if (message.line != null && message.line.length) + for (var i = 0; i < message.line.length; ++i) + $root.perftools.profiles.Line.encode( + message.line[i], + writer.uint32(/* id 4, wireType 2 =*/ 34).fork(), + ).ldelim() + if (message.isFolded != null && message.hasOwnProperty('isFolded')) + writer.uint32(/* id 5, wireType 0 =*/ 40).bool(message.isFolded) + return writer + } + + /** + * Encodes the specified Location message, length delimited. Does not implicitly {@link perftools.profiles.Location.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Location + * @static + * @param {perftools.profiles.ILocation} message Location message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Location.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Location message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Location + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Location} Location + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Location.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Location() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.id = reader.uint64() + break + case 2: + message.mappingId = reader.uint64() + break + case 3: + message.address = reader.uint64() + break + case 4: + if (!(message.line && message.line.length)) message.line = [] + message.line.push($root.perftools.profiles.Line.decode(reader, reader.uint32())) + break + case 5: + message.isFolded = reader.bool() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Location message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Location + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Location} Location + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Location.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Location message. + * @function verify + * @memberof perftools.profiles.Location + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Location.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.id != null && message.hasOwnProperty('id')) + if ( + !$util.isInteger(message.id) && + !(message.id && $util.isInteger(message.id.low) && $util.isInteger(message.id.high)) + ) + return 'id: integer|Long expected' + if (message.mappingId != null && message.hasOwnProperty('mappingId')) + if ( + !$util.isInteger(message.mappingId) && + !( + message.mappingId && + $util.isInteger(message.mappingId.low) && + $util.isInteger(message.mappingId.high) + ) + ) + return 'mappingId: integer|Long expected' + if (message.address != null && message.hasOwnProperty('address')) + if ( + !$util.isInteger(message.address) && + !( + message.address && + $util.isInteger(message.address.low) && + $util.isInteger(message.address.high) + ) + ) + return 'address: integer|Long expected' + if (message.line != null && message.hasOwnProperty('line')) { + if (!Array.isArray(message.line)) return 'line: array expected' + for (var i = 0; i < message.line.length; ++i) { + var error = $root.perftools.profiles.Line.verify(message.line[i]) + if (error) return 'line.' + error + } + } + if (message.isFolded != null && message.hasOwnProperty('isFolded')) + if (typeof message.isFolded !== 'boolean') return 'isFolded: boolean expected' + return null + } + + /** + * Creates a Location message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Location + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Location} Location + */ + Location.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Location) return object + var message = new $root.perftools.profiles.Location() + if (object.id != null) + if ($util.Long) (message.id = $util.Long.fromValue(object.id)).unsigned = true + else if (typeof object.id === 'string') message.id = parseInt(object.id, 10) + else if (typeof object.id === 'number') message.id = object.id + else if (typeof object.id === 'object') + message.id = new $util.LongBits(object.id.low >>> 0, object.id.high >>> 0).toNumber( + true, + ) + if (object.mappingId != null) + if ($util.Long) + (message.mappingId = $util.Long.fromValue(object.mappingId)).unsigned = true + else if (typeof object.mappingId === 'string') + message.mappingId = parseInt(object.mappingId, 10) + else if (typeof object.mappingId === 'number') message.mappingId = object.mappingId + else if (typeof object.mappingId === 'object') + message.mappingId = new $util.LongBits( + object.mappingId.low >>> 0, + object.mappingId.high >>> 0, + ).toNumber(true) + if (object.address != null) + if ($util.Long) (message.address = $util.Long.fromValue(object.address)).unsigned = true + else if (typeof object.address === 'string') + message.address = parseInt(object.address, 10) + else if (typeof object.address === 'number') message.address = object.address + else if (typeof object.address === 'object') + message.address = new $util.LongBits( + object.address.low >>> 0, + object.address.high >>> 0, + ).toNumber(true) + if (object.line) { + if (!Array.isArray(object.line)) + throw TypeError('.perftools.profiles.Location.line: array expected') + message.line = [] + for (var i = 0; i < object.line.length; ++i) { + if (typeof object.line[i] !== 'object') + throw TypeError('.perftools.profiles.Location.line: object expected') + message.line[i] = $root.perftools.profiles.Line.fromObject(object.line[i]) + } + } + if (object.isFolded != null) message.isFolded = Boolean(object.isFolded) + return message + } + + /** + * Creates a plain object from a Location message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Location + * @static + * @param {perftools.profiles.Location} message Location + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Location.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.arrays || options.defaults) object.line = [] + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.id = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.id = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.mappingId = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.mappingId = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.address = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.address = options.longs === String ? '0' : 0 + object.isFolded = false + } + if (message.id != null && message.hasOwnProperty('id')) + if (typeof message.id === 'number') + object.id = options.longs === String ? String(message.id) : message.id + else + object.id = + options.longs === String + ? $util.Long.prototype.toString.call(message.id) + : options.longs === Number + ? new $util.LongBits(message.id.low >>> 0, message.id.high >>> 0).toNumber(true) + : message.id + if (message.mappingId != null && message.hasOwnProperty('mappingId')) + if (typeof message.mappingId === 'number') + object.mappingId = + options.longs === String ? String(message.mappingId) : message.mappingId + else + object.mappingId = + options.longs === String + ? $util.Long.prototype.toString.call(message.mappingId) + : options.longs === Number + ? new $util.LongBits( + message.mappingId.low >>> 0, + message.mappingId.high >>> 0, + ).toNumber(true) + : message.mappingId + if (message.address != null && message.hasOwnProperty('address')) + if (typeof message.address === 'number') + object.address = options.longs === String ? String(message.address) : message.address + else + object.address = + options.longs === String + ? $util.Long.prototype.toString.call(message.address) + : options.longs === Number + ? new $util.LongBits( + message.address.low >>> 0, + message.address.high >>> 0, + ).toNumber(true) + : message.address + if (message.line && message.line.length) { + object.line = [] + for (var j = 0; j < message.line.length; ++j) + object.line[j] = $root.perftools.profiles.Line.toObject(message.line[j], options) + } + if (message.isFolded != null && message.hasOwnProperty('isFolded')) + object.isFolded = message.isFolded + return object + } + + /** + * Converts this Location to JSON. + * @function toJSON + * @memberof perftools.profiles.Location + * @instance + * @returns {Object.} JSON object + */ + Location.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Location + })() + + profiles.Line = (function() { + /** + * Properties of a Line. + * @memberof perftools.profiles + * @interface ILine + * @property {number|Long|null} [functionId] Line functionId + * @property {number|Long|null} [line] Line line + */ + + /** + * Constructs a new Line. + * @memberof perftools.profiles + * @classdesc Represents a Line. + * @implements ILine + * @constructor + * @param {perftools.profiles.ILine=} [properties] Properties to set + */ + function Line(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Line functionId. + * @member {number|Long} functionId + * @memberof perftools.profiles.Line + * @instance + */ + Line.prototype.functionId = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Line line. + * @member {number|Long} line + * @memberof perftools.profiles.Line + * @instance + */ + Line.prototype.line = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Creates a new Line instance using the specified properties. + * @function create + * @memberof perftools.profiles.Line + * @static + * @param {perftools.profiles.ILine=} [properties] Properties to set + * @returns {perftools.profiles.Line} Line instance + */ + Line.create = function create(properties) { + return new Line(properties) + } + + /** + * Encodes the specified Line message. Does not implicitly {@link perftools.profiles.Line.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Line + * @static + * @param {perftools.profiles.ILine} message Line message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Line.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.functionId != null && message.hasOwnProperty('functionId')) + writer.uint32(/* id 1, wireType 0 =*/ 8).uint64(message.functionId) + if (message.line != null && message.hasOwnProperty('line')) + writer.uint32(/* id 2, wireType 0 =*/ 16).int64(message.line) + return writer + } + + /** + * Encodes the specified Line message, length delimited. Does not implicitly {@link perftools.profiles.Line.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Line + * @static + * @param {perftools.profiles.ILine} message Line message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Line.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Line message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Line + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Line} Line + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Line.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Line() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.functionId = reader.uint64() + break + case 2: + message.line = reader.int64() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Line message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Line + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Line} Line + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Line.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Line message. + * @function verify + * @memberof perftools.profiles.Line + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Line.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.functionId != null && message.hasOwnProperty('functionId')) + if ( + !$util.isInteger(message.functionId) && + !( + message.functionId && + $util.isInteger(message.functionId.low) && + $util.isInteger(message.functionId.high) + ) + ) + return 'functionId: integer|Long expected' + if (message.line != null && message.hasOwnProperty('line')) + if ( + !$util.isInteger(message.line) && + !( + message.line && + $util.isInteger(message.line.low) && + $util.isInteger(message.line.high) + ) + ) + return 'line: integer|Long expected' + return null + } + + /** + * Creates a Line message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Line + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Line} Line + */ + Line.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Line) return object + var message = new $root.perftools.profiles.Line() + if (object.functionId != null) + if ($util.Long) + (message.functionId = $util.Long.fromValue(object.functionId)).unsigned = true + else if (typeof object.functionId === 'string') + message.functionId = parseInt(object.functionId, 10) + else if (typeof object.functionId === 'number') message.functionId = object.functionId + else if (typeof object.functionId === 'object') + message.functionId = new $util.LongBits( + object.functionId.low >>> 0, + object.functionId.high >>> 0, + ).toNumber(true) + if (object.line != null) + if ($util.Long) (message.line = $util.Long.fromValue(object.line)).unsigned = false + else if (typeof object.line === 'string') message.line = parseInt(object.line, 10) + else if (typeof object.line === 'number') message.line = object.line + else if (typeof object.line === 'object') + message.line = new $util.LongBits( + object.line.low >>> 0, + object.line.high >>> 0, + ).toNumber() + return message + } + + /** + * Creates a plain object from a Line message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Line + * @static + * @param {perftools.profiles.Line} message Line + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Line.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.functionId = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.functionId = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.line = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.line = options.longs === String ? '0' : 0 + } + if (message.functionId != null && message.hasOwnProperty('functionId')) + if (typeof message.functionId === 'number') + object.functionId = + options.longs === String ? String(message.functionId) : message.functionId + else + object.functionId = + options.longs === String + ? $util.Long.prototype.toString.call(message.functionId) + : options.longs === Number + ? new $util.LongBits( + message.functionId.low >>> 0, + message.functionId.high >>> 0, + ).toNumber(true) + : message.functionId + if (message.line != null && message.hasOwnProperty('line')) + if (typeof message.line === 'number') + object.line = options.longs === String ? String(message.line) : message.line + else + object.line = + options.longs === String + ? $util.Long.prototype.toString.call(message.line) + : options.longs === Number + ? new $util.LongBits(message.line.low >>> 0, message.line.high >>> 0).toNumber() + : message.line + return object + } + + /** + * Converts this Line to JSON. + * @function toJSON + * @memberof perftools.profiles.Line + * @instance + * @returns {Object.} JSON object + */ + Line.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Line + })() + + profiles.Function = (function() { + /** + * Properties of a Function. + * @memberof perftools.profiles + * @interface IFunction + * @property {number|Long|null} [id] Function id + * @property {number|Long|null} [name] Function name + * @property {number|Long|null} [systemName] Function systemName + * @property {number|Long|null} [filename] Function filename + * @property {number|Long|null} [startLine] Function startLine + */ + + /** + * Constructs a new Function. + * @memberof perftools.profiles + * @classdesc Represents a Function. + * @implements IFunction + * @constructor + * @param {perftools.profiles.IFunction=} [properties] Properties to set + */ + function Function(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) this[keys[i]] = properties[keys[i]] + } + + /** + * Function id. + * @member {number|Long} id + * @memberof perftools.profiles.Function + * @instance + */ + Function.prototype.id = $util.Long ? $util.Long.fromBits(0, 0, true) : 0 + + /** + * Function name. + * @member {number|Long} name + * @memberof perftools.profiles.Function + * @instance + */ + Function.prototype.name = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Function systemName. + * @member {number|Long} systemName + * @memberof perftools.profiles.Function + * @instance + */ + Function.prototype.systemName = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Function filename. + * @member {number|Long} filename + * @memberof perftools.profiles.Function + * @instance + */ + Function.prototype.filename = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Function startLine. + * @member {number|Long} startLine + * @memberof perftools.profiles.Function + * @instance + */ + Function.prototype.startLine = $util.Long ? $util.Long.fromBits(0, 0, false) : 0 + + /** + * Creates a new Function instance using the specified properties. + * @function create + * @memberof perftools.profiles.Function + * @static + * @param {perftools.profiles.IFunction=} [properties] Properties to set + * @returns {perftools.profiles.Function} Function instance + */ + Function.create = function create(properties) { + return new Function(properties) + } + + /** + * Encodes the specified Function message. Does not implicitly {@link perftools.profiles.Function.verify|verify} messages. + * @function encode + * @memberof perftools.profiles.Function + * @static + * @param {perftools.profiles.IFunction} message Function message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Function.encode = function encode(message, writer) { + if (!writer) writer = $Writer.create() + if (message.id != null && message.hasOwnProperty('id')) + writer.uint32(/* id 1, wireType 0 =*/ 8).uint64(message.id) + if (message.name != null && message.hasOwnProperty('name')) + writer.uint32(/* id 2, wireType 0 =*/ 16).int64(message.name) + if (message.systemName != null && message.hasOwnProperty('systemName')) + writer.uint32(/* id 3, wireType 0 =*/ 24).int64(message.systemName) + if (message.filename != null && message.hasOwnProperty('filename')) + writer.uint32(/* id 4, wireType 0 =*/ 32).int64(message.filename) + if (message.startLine != null && message.hasOwnProperty('startLine')) + writer.uint32(/* id 5, wireType 0 =*/ 40).int64(message.startLine) + return writer + } + + /** + * Encodes the specified Function message, length delimited. Does not implicitly {@link perftools.profiles.Function.verify|verify} messages. + * @function encodeDelimited + * @memberof perftools.profiles.Function + * @static + * @param {perftools.profiles.IFunction} message Function message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Function.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim() + } + + /** + * Decodes a Function message from the specified reader or buffer. + * @function decode + * @memberof perftools.profiles.Function + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {perftools.profiles.Function} Function + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Function.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) reader = $Reader.create(reader) + var end = length === undefined ? reader.len : reader.pos + length, + message = new $root.perftools.profiles.Function() + while (reader.pos < end) { + var tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.id = reader.uint64() + break + case 2: + message.name = reader.int64() + break + case 3: + message.systemName = reader.int64() + break + case 4: + message.filename = reader.int64() + break + case 5: + message.startLine = reader.int64() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + } + + /** + * Decodes a Function message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof perftools.profiles.Function + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {perftools.profiles.Function} Function + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Function.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) reader = new $Reader(reader) + return this.decode(reader, reader.uint32()) + } + + /** + * Verifies a Function message. + * @function verify + * @memberof perftools.profiles.Function + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Function.verify = function verify(message) { + if (typeof message !== 'object' || message === null) return 'object expected' + if (message.id != null && message.hasOwnProperty('id')) + if ( + !$util.isInteger(message.id) && + !(message.id && $util.isInteger(message.id.low) && $util.isInteger(message.id.high)) + ) + return 'id: integer|Long expected' + if (message.name != null && message.hasOwnProperty('name')) + if ( + !$util.isInteger(message.name) && + !( + message.name && + $util.isInteger(message.name.low) && + $util.isInteger(message.name.high) + ) + ) + return 'name: integer|Long expected' + if (message.systemName != null && message.hasOwnProperty('systemName')) + if ( + !$util.isInteger(message.systemName) && + !( + message.systemName && + $util.isInteger(message.systemName.low) && + $util.isInteger(message.systemName.high) + ) + ) + return 'systemName: integer|Long expected' + if (message.filename != null && message.hasOwnProperty('filename')) + if ( + !$util.isInteger(message.filename) && + !( + message.filename && + $util.isInteger(message.filename.low) && + $util.isInteger(message.filename.high) + ) + ) + return 'filename: integer|Long expected' + if (message.startLine != null && message.hasOwnProperty('startLine')) + if ( + !$util.isInteger(message.startLine) && + !( + message.startLine && + $util.isInteger(message.startLine.low) && + $util.isInteger(message.startLine.high) + ) + ) + return 'startLine: integer|Long expected' + return null + } + + /** + * Creates a Function message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof perftools.profiles.Function + * @static + * @param {Object.} object Plain object + * @returns {perftools.profiles.Function} Function + */ + Function.fromObject = function fromObject(object) { + if (object instanceof $root.perftools.profiles.Function) return object + var message = new $root.perftools.profiles.Function() + if (object.id != null) + if ($util.Long) (message.id = $util.Long.fromValue(object.id)).unsigned = true + else if (typeof object.id === 'string') message.id = parseInt(object.id, 10) + else if (typeof object.id === 'number') message.id = object.id + else if (typeof object.id === 'object') + message.id = new $util.LongBits(object.id.low >>> 0, object.id.high >>> 0).toNumber( + true, + ) + if (object.name != null) + if ($util.Long) (message.name = $util.Long.fromValue(object.name)).unsigned = false + else if (typeof object.name === 'string') message.name = parseInt(object.name, 10) + else if (typeof object.name === 'number') message.name = object.name + else if (typeof object.name === 'object') + message.name = new $util.LongBits( + object.name.low >>> 0, + object.name.high >>> 0, + ).toNumber() + if (object.systemName != null) + if ($util.Long) + (message.systemName = $util.Long.fromValue(object.systemName)).unsigned = false + else if (typeof object.systemName === 'string') + message.systemName = parseInt(object.systemName, 10) + else if (typeof object.systemName === 'number') message.systemName = object.systemName + else if (typeof object.systemName === 'object') + message.systemName = new $util.LongBits( + object.systemName.low >>> 0, + object.systemName.high >>> 0, + ).toNumber() + if (object.filename != null) + if ($util.Long) + (message.filename = $util.Long.fromValue(object.filename)).unsigned = false + else if (typeof object.filename === 'string') + message.filename = parseInt(object.filename, 10) + else if (typeof object.filename === 'number') message.filename = object.filename + else if (typeof object.filename === 'object') + message.filename = new $util.LongBits( + object.filename.low >>> 0, + object.filename.high >>> 0, + ).toNumber() + if (object.startLine != null) + if ($util.Long) + (message.startLine = $util.Long.fromValue(object.startLine)).unsigned = false + else if (typeof object.startLine === 'string') + message.startLine = parseInt(object.startLine, 10) + else if (typeof object.startLine === 'number') message.startLine = object.startLine + else if (typeof object.startLine === 'object') + message.startLine = new $util.LongBits( + object.startLine.low >>> 0, + object.startLine.high >>> 0, + ).toNumber() + return message + } + + /** + * Creates a plain object from a Function message. Also converts values to other types if specified. + * @function toObject + * @memberof perftools.profiles.Function + * @static + * @param {perftools.profiles.Function} message Function + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Function.toObject = function toObject(message, options) { + if (!options) options = {} + var object = {} + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true) + object.id = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.id = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.name = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.name = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.systemName = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.systemName = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.filename = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.filename = options.longs === String ? '0' : 0 + if ($util.Long) { + var long = new $util.Long(0, 0, false) + object.startLine = + options.longs === String + ? long.toString() + : options.longs === Number + ? long.toNumber() + : long + } else object.startLine = options.longs === String ? '0' : 0 + } + if (message.id != null && message.hasOwnProperty('id')) + if (typeof message.id === 'number') + object.id = options.longs === String ? String(message.id) : message.id + else + object.id = + options.longs === String + ? $util.Long.prototype.toString.call(message.id) + : options.longs === Number + ? new $util.LongBits(message.id.low >>> 0, message.id.high >>> 0).toNumber(true) + : message.id + if (message.name != null && message.hasOwnProperty('name')) + if (typeof message.name === 'number') + object.name = options.longs === String ? String(message.name) : message.name + else + object.name = + options.longs === String + ? $util.Long.prototype.toString.call(message.name) + : options.longs === Number + ? new $util.LongBits(message.name.low >>> 0, message.name.high >>> 0).toNumber() + : message.name + if (message.systemName != null && message.hasOwnProperty('systemName')) + if (typeof message.systemName === 'number') + object.systemName = + options.longs === String ? String(message.systemName) : message.systemName + else + object.systemName = + options.longs === String + ? $util.Long.prototype.toString.call(message.systemName) + : options.longs === Number + ? new $util.LongBits( + message.systemName.low >>> 0, + message.systemName.high >>> 0, + ).toNumber() + : message.systemName + if (message.filename != null && message.hasOwnProperty('filename')) + if (typeof message.filename === 'number') + object.filename = options.longs === String ? String(message.filename) : message.filename + else + object.filename = + options.longs === String + ? $util.Long.prototype.toString.call(message.filename) + : options.longs === Number + ? new $util.LongBits( + message.filename.low >>> 0, + message.filename.high >>> 0, + ).toNumber() + : message.filename + if (message.startLine != null && message.hasOwnProperty('startLine')) + if (typeof message.startLine === 'number') + object.startLine = + options.longs === String ? String(message.startLine) : message.startLine + else + object.startLine = + options.longs === String + ? $util.Long.prototype.toString.call(message.startLine) + : options.longs === Number + ? new $util.LongBits( + message.startLine.low >>> 0, + message.startLine.high >>> 0, + ).toNumber() + : message.startLine + return object + } + + /** + * Converts this Function to JSON. + * @function toJSON + * @memberof perftools.profiles.Function + * @instance + * @returns {Object.} JSON object + */ + Function.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions) + } + + return Function + })() + + return profiles + })() + + return perftools +})() + +module.exports = $root diff --git a/src/import/utils.ts b/src/import/utils.ts new file mode 100644 index 0000000..22829b5 --- /dev/null +++ b/src/import/utils.ts @@ -0,0 +1,83 @@ +import * as pako from 'pako' + +export interface ProfileDataSource { + name(): Promise + readAsArrayBuffer(): Promise + readAsText(): Promise +} + +export class TextProfileDataSource implements ProfileDataSource { + constructor(private fileName: string, private contents: string) {} + async name() { + return this.fileName + } + async readAsArrayBuffer() { + // JavaScript strings are UTF-16 encoded, but if this string is + // constructed based on + + // TODO(jlfwong): Might want to make this construct an array + // buffer based on the text + return new ArrayBuffer(0) + } + async readAsText() { + return this.contents + } +} + +export class MaybeCompressedDataReader implements ProfileDataSource { + private uncompressedData: Promise + + constructor( + private namePromise: Promise, + maybeCompressedDataPromise: Promise, + ) { + this.uncompressedData = maybeCompressedDataPromise.then(async (fileData: ArrayBuffer) => { + try { + const result = pako.inflate(new Uint8Array(fileData)).buffer + return result + } catch (e) { + return fileData + } + }) + } + + async name(): Promise { + return await this.namePromise + } + + async readAsArrayBuffer(): Promise { + return await this.uncompressedData + } + + async readAsText(): Promise { + const buffer = await this.readAsArrayBuffer() + let ret: string = '' + + // JavaScript strings are UTF-16 encoded, but we're reading data + // from disk that we're going to asusme is UTF-8 encoded. + const array = new Uint8Array(buffer) + for (let i = 0; i < array.length; i++) { + ret += String.fromCharCode(array[i]) + } + return ret + } + + static fromFile(file: File): MaybeCompressedDataReader { + const maybeCompressedDataPromise: Promise = new Promise(resolve => { + const reader = new FileReader() + reader.addEventListener('loadend', () => { + if (!(reader.result instanceof ArrayBuffer)) { + throw new Error('Expected reader.result to be an instance of ArrayBuffer') + } + resolve(reader.result) + }) + reader.readAsArrayBuffer(file) + }) + + return new MaybeCompressedDataReader(Promise.resolve(file.name), maybeCompressedDataPromise) + } + + static fromArrayBuffer(name: string, buffer: ArrayBuffer): MaybeCompressedDataReader { + return new MaybeCompressedDataReader(Promise.resolve(name), Promise.resolve(buffer)) + } +} diff --git a/src/lib/test-utils.ts b/src/lib/test-utils.ts index ced2c7b..b1c835a 100644 --- a/src/lib/test-utils.ts +++ b/src/lib/test-utils.ts @@ -1,8 +1,8 @@ import * as fs from 'fs' import * as path from 'path' import {Profile, CallTreeNode, Frame} from './profile' -import {importProfileGroup} from '../import' import {exportProfileGroup, importSpeedscopeProfiles} from './file-format' +import {importProfilesFromArrayBuffer} from '../import' interface DumpedProfile { name: string @@ -47,9 +47,10 @@ export function dumpProfile(profile: Profile): any { } export async function checkProfileSnapshot(filepath: string) { - const input = fs.readFileSync(filepath, 'utf8') + const buffer = fs.readFileSync(filepath) + const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) - const profileGroup = await importProfileGroup(path.basename(filepath), input) + const profileGroup = await importProfilesFromArrayBuffer(path.basename(filepath), arrayBuffer) if (profileGroup) { expect(profileGroup.name).toMatchSnapshot('profileGroup.name') expect(profileGroup.indexToView).toMatchSnapshot('indexToView') @@ -62,7 +63,7 @@ export async function checkProfileSnapshot(filepath: string) { return } - const profilesWithoutFilename = await importProfileGroup('unknown', input) + const profilesWithoutFilename = await importProfilesFromArrayBuffer('unknown', arrayBuffer) if (profilesWithoutFilename) { expect(profilesWithoutFilename.profiles.length).toEqual(profileGroup.profiles.length) profilesWithoutFilename.name = profileGroup.name diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index 3c6e6bf..977cb03 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -13,8 +13,11 @@ import { memoizeByReference, memoizeByShallowEquality, objectsHaveShallowEquality, + decodeBase64, } from './utils' +import * as jsc from 'jsverify' + test('sortBy', () => { const ls = ['a3', 'b2', 'c1', 'd4'] sortBy(ls, k => k.charCodeAt(1)) @@ -173,3 +176,19 @@ test('objectsHaveShallowEquality', () => { expect(objectsHaveShallowEquality([1], [1, 2])).toBe(false) expect(objectsHaveShallowEquality([1, 2], [1])).toBe(false) }) + +test('decodeBase64', () => { + jsc.assertForall(jsc.array(jsc.uint8), byteArray => { + let binaryString = '' + for (let byte of byteArray) { + binaryString += String.fromCharCode(byte) + } + const b64string = btoa(binaryString) + const decoded = decodeBase64(b64string) + + expect(Uint8Array.from(byteArray)).toEqual(decoded) + + // If the above expect(...) assertion fails, we won't reach here. + return true + }) +}) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ccd77bc..b1dec30 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -167,3 +167,131 @@ export function memoizeByReference(cb: (t: T) => U): (t: T) => U { } } } + +export function lazyStatic(cb: () => T): () => T { + let last: {result: T} | null = null + return () => { + if (last == null) { + last = {result: cb()} + } + return last.result + } +} + +const base64lookupTable = lazyStatic((): Map => { + const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + const ret = new Map() + for (let i = 0; i < alphabet.length; i++) { + ret.set(alphabet.charAt(i), i) + } + ret.set('=', -1) + return ret +}) + +// NOTE: There are probably simpler solutions to this problem, but I have this written already, so +// until we run into problems with this, let's just use this. +// +// See: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_Unicode_Problem#The_Unicode_Problem +export function decodeBase64(encoded: string): Uint8Array { + // Reference: https://www.rfc-editor.org/rfc/rfc4648.txt + + const lookupTable = base64lookupTable() + + // 3 byte groups are represented as sequneces of 4 characters. + // + // "The encoding process represents 24-bit groups of input bits as output + // strings of 4 encoded characters." + // + // "Special processing is performed if fewer than 24 bits are available + // at the end of the data being encoded. A full encoding quantum is + // always completed at the end of a quantity. When fewer than 24 input + // bits are available in an input group bits with value zero are added + // (on the right) to form an integral number of 6-bit groups." + + if (encoded.length % 4 !== 0) { + throw new Error( + `Invalid length for base64 encoded string. Expected length % 4 = 0, got length = ${ + encoded.length + }`, + ) + } + + const quartetCount = encoded.length / 4 + let byteCount: number + + // Special processing is performed if fewer than 24 bits are available + // at the end of the data being encoded. A full encoding quantum is + // always completed at the end of a quantity. When fewer than 24 input + // bits are available in an input group, bits with value zero are added + // (on the right) to form an integral number of 6-bit groups. Padding + // at the end of the data is performed using the '=' character. Since + // all base 64 input is an integral number of octets, only the following + // cases can arise: + // + // (1) The final quantum of encoding input is an integral multiple of 24 + // bits; here, the final unit of encoded output will be an integral + // multiple of 4 characters with no "=" padding. + // + // (2) The final quantum of encoding input is exactly 8 bits; here, the + // final unit of encoded output will be two characters followed by + // two "=" padding characters. + // + // (3) The final quantum of encoding input is exactly 16 bits; here, the + // final unit of encoded output will be three characters followed by + // one "=" padding character. + if (encoded.length >= 4) { + if (encoded.charAt(encoded.length - 1) === '=') { + if (encoded.charAt(encoded.length - 2) === '=') { + // Case (2) + byteCount = quartetCount * 3 - 2 + } else { + // Case (3) + byteCount = quartetCount * 3 - 1 + } + } else { + // Case (1) + byteCount = quartetCount * 3 + } + } else { + // Case (1) + byteCount = quartetCount * 3 + } + + const bytes = new Uint8Array(byteCount) + let offset = 0 + + for (let i = 0; i < quartetCount; i++) { + const enc1 = encoded.charAt(i * 4 + 0) + const enc2 = encoded.charAt(i * 4 + 1) + const enc3 = encoded.charAt(i * 4 + 2) + const enc4 = encoded.charAt(i * 4 + 3) + + const sextet1 = lookupTable.get(enc1) + const sextet2 = lookupTable.get(enc2) + const sextet3 = lookupTable.get(enc3) + const sextet4 = lookupTable.get(enc4) + + if (sextet1 == null || sextet2 == null || sextet3 == null || sextet4 == null) { + throw new Error( + `Invalid quartet at indices ${i * 4} .. ${i * 4 + 3}: ${encoded.substring( + i * 4, + i * 4 + 3, + )}`, + ) + } + + bytes[offset++] = (sextet1 << 2) | (sextet2 >> 4) + if (enc3 !== '=') { + bytes[offset++] = ((sextet2 & 15) << 4) | (sextet3 >> 2) + } + if (enc4 !== '=') { + bytes[offset++] = ((sextet3 & 7) << 6) | sextet4 + } + } + + if (offset !== byteCount) { + throw new Error(`Expected to decode ${byteCount} bytes, but only decoded ${offset})`) + } + + return bytes +} diff --git a/src/views/application.tsx b/src/views/application.tsx index dfd3dca..139cfb2 100644 --- a/src/views/application.tsx +++ b/src/views/application.tsx @@ -18,8 +18,23 @@ import {Graphics} from '../gl/graphics' const importModule = import('../import') // Force eager loading of the module importModule.then(() => {}) -async function importProfiles(fileName: string, contents: string): Promise { - return (await importModule).importProfileGroup(fileName, contents) + +async function importProfilesFromText( + fileName: string, + contents: string, +): Promise { + return (await importModule).importProfileGroupFromText(fileName, contents) +} + +async function importProfilesFromBase64( + fileName: string, + contents: string, +): Promise { + return (await importModule).importProfileGroupFromBase64(fileName, contents) +} + +async function importProfilesFromFile(file: File): Promise { + return (await importModule).importProfilesFromFile(file) } async function importFromFileSystemDirectoryEntry(entry: FileSystemDirectoryEntry) { return (await importModule).importFromFileSystemDirectoryEntry(entry) @@ -320,16 +335,7 @@ export class Application extends StatelessComponent { loadFromFile(file: File) { this.loadProfile(async () => { - const reader = new FileReader() - const loadPromise = new Promise(resolve => reader.addEventListener('loadend', resolve)) - reader.readAsText(file) - await loadPromise - - if (typeof reader.result !== 'string') { - throw new Error('Expected ArrayBuffer') - } - - const profiles = await importProfiles(file.name, reader.result) + const profiles = await importProfilesFromFile(file) if (profiles) { for (let profile of profiles.profiles) { if (!profile.getName()) { @@ -344,7 +350,19 @@ export class Application extends StatelessComponent { // a symbol map. If that's the case, we want to parse it, and apply the symbol // mapping to the already loaded profile. This can be use to take an opaque // profile and make it readable. - const map = importEmscriptenSymbolMap(reader.result) + const reader = new FileReader() + const fileContentsPromise = new Promise(resolve => { + reader.addEventListener('loadend', () => { + if (typeof reader.result !== 'string') { + throw new Error('Expected reader.result to be a string') + } + resolve(reader.result) + }) + }) + reader.readAsText(file) + const fileContents = await fileContentsPromise + + const map = importEmscriptenSymbolMap(fileContents) if (map) { const {profile, index} = this.props.activeProfileState console.log('Importing as emscripten symbol map') @@ -365,7 +383,7 @@ export class Application extends StatelessComponent { this.loadProfile(async () => { const filename = 'perf-vertx-stacks-01-collapsed-all.txt' const data = await fetch(exampleProfileURL).then(resp => resp.text()) - return await importProfiles(filename, data) + return await importProfilesFromText(filename, data) }) } @@ -463,7 +481,7 @@ export class Application extends StatelessComponent { const pasted = (ev as ClipboardEvent).clipboardData.getData('text') this.loadProfile(async () => { - return await importProfiles('From Clipboard', pasted) + return await importProfilesFromText('From Clipboard', pasted) }) } @@ -489,12 +507,12 @@ export class Application extends StatelessComponent { return } this.loadProfile(async () => { - const response = await fetch(this.props.hashParams.profileURL!) + const response: Response = await fetch(this.props.hashParams.profileURL!) let filename = new URL(this.props.hashParams.profileURL!).pathname if (filename.includes('/')) { filename = filename.slice(filename.lastIndexOf('/') + 1) } - return await importProfiles(filename, await response.text()) + return await importProfilesFromText(filename, await response.text()) }) } else if (this.props.hashParams.localProfilePath) { // There isn't good cross-browser support for XHR of local files, even from @@ -502,8 +520,7 @@ export class Application extends StatelessComponent { // as a JavaScript file which will invoke a global function. ;(window as any)['speedscope'] = { loadFileFromBase64: (filename: string, base64source: string) => { - const source = atob(base64source) - this.loadProfile(() => importProfiles(filename, source)) + this.loadProfile(() => importProfilesFromBase64(filename, base64source)) }, }