diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2019-01-08 19:23:33 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2019-01-08 21:48:06 +0800 |
commit | 2c974b5f3ffa0e9736000273e39cdeee4a251b94 (patch) | |
tree | a1772f93d796e3b4ba7a988194a44a3e8bcd6d31 /packages/sol-profiler | |
parent | 0ac36cef288deecd36caa601c53d13517eef5ca8 (diff) | |
download | dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.tar dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.tar.gz dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.tar.bz2 dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.tar.lz dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.tar.xz dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.tar.zst dexon-0x-contracts-2c974b5f3ffa0e9736000273e39cdeee4a251b94.zip |
Refactor out sol-cov, sol-profiler and sol-trace into their separate packages
Diffstat (limited to 'packages/sol-profiler')
-rw-r--r-- | packages/sol-profiler/.npmignore | 6 | ||||
-rw-r--r-- | packages/sol-profiler/CHANGELOG.json | 12 | ||||
-rw-r--r-- | packages/sol-profiler/README.md | 75 | ||||
-rw-r--r-- | packages/sol-profiler/package.json | 50 | ||||
-rw-r--r-- | packages/sol-profiler/src/globals.d.ts | 7 | ||||
-rw-r--r-- | packages/sol-profiler/src/index.ts | 25 | ||||
-rw-r--r-- | packages/sol-profiler/src/profiler_subprovider.ts | 98 | ||||
-rw-r--r-- | packages/sol-profiler/tsconfig.json | 8 | ||||
-rw-r--r-- | packages/sol-profiler/tslint.json | 3 | ||||
-rw-r--r-- | packages/sol-profiler/typedoc-tsconfig.json | 7 |
10 files changed, 291 insertions, 0 deletions
diff --git a/packages/sol-profiler/.npmignore b/packages/sol-profiler/.npmignore new file mode 100644 index 000000000..037786e46 --- /dev/null +++ b/packages/sol-profiler/.npmignore @@ -0,0 +1,6 @@ +.* +yarn-error.log +/src/ +/scripts/ +tsconfig.json +/lib/src/monorepo_scripts/ diff --git a/packages/sol-profiler/CHANGELOG.json b/packages/sol-profiler/CHANGELOG.json new file mode 100644 index 000000000..ca6048d99 --- /dev/null +++ b/packages/sol-profiler/CHANGELOG.json @@ -0,0 +1,12 @@ +[ + { + "version": "1.0.0", + "changes": [ + { + "note": + "Initial release as a separate package. For historic entries check @0x/sol-trace-based-tools-common", + "pr": 1492 + } + ] + } +] diff --git a/packages/sol-profiler/README.md b/packages/sol-profiler/README.md new file mode 100644 index 000000000..44fa29e3f --- /dev/null +++ b/packages/sol-profiler/README.md @@ -0,0 +1,75 @@ +## @0x/sol-profiler + +Solidity line-by-line gas profiler. + +### Read the [Documentation](https://0xproject.com/docs/sol-profiler). + +## Installation + +```bash +yarn add @0x/sol-profiler +``` + +**Import** + +```javascript +import { ProfilerSubprovider } from '@0x/sol-profiler'; +``` + +or + +```javascript +var ProfilerSubprovider = require('@0x/sol-profiler').ProfilerSubprovider; +``` + +## Contributing + +We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: + +```bash +PKG=@0x/sol-profiler yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0x/sol-profiler yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/packages/sol-profiler/package.json b/packages/sol-profiler/package.json new file mode 100644 index 000000000..03b421b0e --- /dev/null +++ b/packages/sol-profiler/package.json @@ -0,0 +1,50 @@ +{ + "name": "@0x/sol-profiler", + "version": "1.0.0", + "engines": { + "node": ">=6.12" + }, + "description": "Generate profiler reports for Solidity code", + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "scripts": { + "build": "tsc -b", + "build:ci": "yarn build", + "lint": "tslint --format stylish --project .", + "clean": "shx rm -rf lib src/artifacts generated_docs", + "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" + }, + "config": { + "postpublish": { + "assets": [] + } + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x-monorepo.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x-monorepo/issues" + }, + "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-profiler/README.md", + "dependencies": { + "@0x/subproviders": "^2.1.8", + "@0x/typescript-typings": "^3.0.6", + "@0x/sol-trace-based-tools-common": "^2.1.16", + "ethereum-types": "^1.1.4", + "lodash": "^4.17.5" + }, + "devDependencies": { + "@0x/tslint-config": "^2.0.0", + "@types/node": "*", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.11.0", + "typedoc": "0.13.0", + "typescript": "3.0.1" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/sol-profiler/src/globals.d.ts b/packages/sol-profiler/src/globals.d.ts new file mode 100644 index 000000000..e799b3529 --- /dev/null +++ b/packages/sol-profiler/src/globals.d.ts @@ -0,0 +1,7 @@ +// tslint:disable:completed-docs +declare module '*.json' { + const json: any; + /* tslint:disable */ + export default json; + /* tslint:enable */ +} diff --git a/packages/sol-profiler/src/index.ts b/packages/sol-profiler/src/index.ts new file mode 100644 index 000000000..b36ed5baa --- /dev/null +++ b/packages/sol-profiler/src/index.ts @@ -0,0 +1,25 @@ +export { + AbstractArtifactAdapter, + SolCompilerArtifactAdapter, + TruffleArtifactAdapter, + ContractData, +} from '@0x/sol-trace-based-tools-common'; + +// HACK: ProfilerSubprovider is a hacky way to do profiling using coverage tools. Not production ready +export { ProfilerSubprovider } from './profiler_subprovider'; + +export { + JSONRPCRequestPayload, + Provider, + JSONRPCErrorCallback, + JSONRPCResponsePayload, + JSONRPCResponseError, +} from 'ethereum-types'; + +export { + JSONRPCRequestPayloadWithMethod, + NextCallback, + ErrorCallback, + OnNextCompleted, + Callback, +} from '@0x/subproviders'; diff --git a/packages/sol-profiler/src/profiler_subprovider.ts b/packages/sol-profiler/src/profiler_subprovider.ts new file mode 100644 index 000000000..61dc25b6b --- /dev/null +++ b/packages/sol-profiler/src/profiler_subprovider.ts @@ -0,0 +1,98 @@ +import * as _ from 'lodash'; + +import { + AbstractArtifactAdapter, + collectCoverageEntries, + ContractData, + Coverage, + SingleFileSubtraceHandler, + SourceRange, + Subtrace, + TraceCollector, + TraceInfo, + TraceInfoSubprovider, + utils, +} from '@0x/sol-trace-based-tools-common'; + +/** + * This class implements the [web3-provider-engine](https://github.com/MetaMask/provider-engine) subprovider interface. + * ProfilerSubprovider is used to profile Solidity code while running tests. + */ +export class ProfilerSubprovider extends TraceInfoSubprovider { + private readonly _profilerCollector: TraceCollector; + /** + * Instantiates a ProfilerSubprovider instance + * @param artifactAdapter Adapter for used artifacts format (0x, truffle, giveth, etc.) + * @param defaultFromAddress default from address to use when sending transactions + * @param isVerbose If true, we will log any unknown transactions. Otherwise we will ignore them + */ + constructor(artifactAdapter: AbstractArtifactAdapter, defaultFromAddress: string, isVerbose: boolean = true) { + const traceCollectionSubproviderConfig = { + shouldCollectTransactionTraces: true, + shouldCollectGasEstimateTraces: false, + shouldCollectCallTraces: false, + }; + super(defaultFromAddress, traceCollectionSubproviderConfig); + this._profilerCollector = new TraceCollector(artifactAdapter, isVerbose, profilerHandler); + } + protected async _handleTraceInfoAsync(traceInfo: TraceInfo): Promise<void> { + await this._profilerCollector.computeSingleTraceCoverageAsync(traceInfo); + } + /** + * Write the test profiler results to a file in Istanbul format. + */ + public async writeProfilerOutputAsync(): Promise<void> { + await this._profilerCollector.writeOutputAsync(); + } +} + +/** + * Computed partial coverage for a single file & subtrace for the purposes of + * gas profiling. + * @param contractData Contract metadata (source, srcMap, bytecode) + * @param subtrace A subset of a transcation/call trace that was executed within that contract + * @param pcToSourceRange A mapping from program counters to source ranges + * @param fileIndex Index of a file to compute coverage for + * @return Partial istanbul coverage for that file & subtrace + */ +export const profilerHandler: SingleFileSubtraceHandler = ( + contractData: ContractData, + subtrace: Subtrace, + pcToSourceRange: { [programCounter: number]: SourceRange }, + fileIndex: number, +): Coverage => { + const absoluteFileName = contractData.sources[fileIndex]; + const profilerEntriesDescription = collectCoverageEntries(contractData.sourceCodes[fileIndex]); + const gasConsumedByStatement: { [statementId: string]: number } = {}; + const statementIds = _.keys(profilerEntriesDescription.statementMap); + for (const statementId of statementIds) { + const statementDescription = profilerEntriesDescription.statementMap[statementId]; + const totalGasCost = _.sum( + _.map(subtrace, structLog => { + const sourceRange = pcToSourceRange[structLog.pc]; + if (_.isUndefined(sourceRange)) { + return 0; + } + if (sourceRange.fileName !== absoluteFileName) { + return 0; + } + if (utils.isRangeInside(sourceRange.location, statementDescription)) { + return structLog.gasCost; + } else { + return 0; + } + }), + ); + gasConsumedByStatement[statementId] = totalGasCost; + } + const partialProfilerOutput = { + [absoluteFileName]: { + ...profilerEntriesDescription, + path: absoluteFileName, + f: {}, // I's meaningless in profiling context + s: gasConsumedByStatement, + b: {}, // I's meaningless in profiling context + }, + }; + return partialProfilerOutput; +}; diff --git a/packages/sol-profiler/tsconfig.json b/packages/sol-profiler/tsconfig.json new file mode 100644 index 000000000..233008d61 --- /dev/null +++ b/packages/sol-profiler/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": "." + }, + "include": ["./src/**/*"] +} diff --git a/packages/sol-profiler/tslint.json b/packages/sol-profiler/tslint.json new file mode 100644 index 000000000..dd9053357 --- /dev/null +++ b/packages/sol-profiler/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": ["@0x/tslint-config"] +} diff --git a/packages/sol-profiler/typedoc-tsconfig.json b/packages/sol-profiler/typedoc-tsconfig.json new file mode 100644 index 000000000..a4c669cb6 --- /dev/null +++ b/packages/sol-profiler/typedoc-tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../typedoc-tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*"] +} |