This repository has been archived by the owner on Jul 9, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 465
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1638 from 0xProject/feature/sol-profiler-improvem…
…ents Sol profiler improvements
- Loading branch information
Showing
17 changed files
with
473 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { TraceInfo } from '@0x/sol-tracing-utils'; | ||
import { logUtils } from '@0x/utils'; | ||
import { OpCode } from 'ethereum-types'; | ||
import { stripHexPrefix } from 'ethereumjs-util'; | ||
import * as _ from 'lodash'; | ||
|
||
const ZERO_BYTE_CALL_DATA_COST = 4; | ||
const NON_ZERO_BYTE_CALL_DATA_COST = 68; | ||
const WORD_SIZE = 32; | ||
const G_MEMORY = 3; | ||
const G_QUAD_COEF = 512; | ||
const HEX_BASE = 16; | ||
const G_COPY = 3; | ||
|
||
export const costUtils = { | ||
reportCallDataCost(traceInfo: TraceInfo): number { | ||
if (_.isUndefined(traceInfo.dataIfExists)) { | ||
// No call data to report | ||
return 0; | ||
} | ||
const callData = traceInfo.dataIfExists; | ||
const callDataBuf = Buffer.from(stripHexPrefix(callData), 'hex'); | ||
const { true: zeroBytesCountIfExist, false: nonZeroBytesCountIfExist } = _.countBy( | ||
callDataBuf, | ||
byte => byte === 0, | ||
); | ||
const zeroBytesCost = (zeroBytesCountIfExist || 0) * ZERO_BYTE_CALL_DATA_COST; | ||
const nonZeroBytesCost = (nonZeroBytesCountIfExist || 0) * NON_ZERO_BYTE_CALL_DATA_COST; | ||
const callDataCost = zeroBytesCost + nonZeroBytesCost; | ||
logUtils.header('Call data breakdown', '-'); | ||
logUtils.table({ | ||
'call data size (bytes)': callData.length, | ||
callDataCost, | ||
zeroBytesCost, | ||
nonZeroBytesCost, | ||
zeroBytesCountIfExist, | ||
nonZeroBytesCountIfExist, | ||
}); | ||
return callDataCost; | ||
}, | ||
reportMemoryCost(traceInfo: TraceInfo): number { | ||
const structLogs = traceInfo.trace.structLogs; | ||
const MEMORY_OPCODES = [OpCode.MLoad, OpCode.MStore, OpCode.MStore8]; | ||
const CALL_DATA_OPCODES = [OpCode.CallDataCopy]; | ||
const memoryLogs = _.filter(structLogs, structLog => | ||
_.includes([...MEMORY_OPCODES, ...CALL_DATA_OPCODES], structLog.op), | ||
); | ||
const memoryLocationsAccessed = _.map(memoryLogs, structLog => { | ||
if (_.includes(CALL_DATA_OPCODES, structLog.op)) { | ||
const memOffset = parseInt(structLog.stack[0], HEX_BASE); | ||
const length = parseInt(structLog.stack[2], HEX_BASE); | ||
return memOffset + length; | ||
} else { | ||
return parseInt(structLog.stack[0], HEX_BASE); | ||
} | ||
}); | ||
const highestMemoryLocationAccessed = _.max(memoryLocationsAccessed); | ||
return costUtils._printMemoryCost(highestMemoryLocationAccessed); | ||
}, | ||
reportCopyingCost(traceInfo: TraceInfo): number { | ||
const structLogs = traceInfo.trace.structLogs; | ||
const COPY_OPCODES = [OpCode.CallDataCopy]; | ||
const copyLogs = _.filter(structLogs, structLog => _.includes(COPY_OPCODES, structLog.op)); | ||
const copyCosts = _.map(copyLogs, structLog => { | ||
const length = parseInt(structLog.stack[2], HEX_BASE); | ||
return Math.ceil(length / WORD_SIZE) * G_COPY; | ||
}); | ||
return _.sum(copyCosts); | ||
}, | ||
reportOpcodesCost(traceInfo: TraceInfo): number { | ||
const structLogs = traceInfo.trace.structLogs; | ||
const gasCosts = _.map(structLogs, structLog => structLog.gasCost); | ||
const gasCost = _.sum(gasCosts); | ||
return gasCost; | ||
}, | ||
_printMemoryCost(highestMemoryLocationAccessed?: number): number { | ||
if (_.isUndefined(highestMemoryLocationAccessed)) { | ||
return 0; | ||
} | ||
const memoryWordsUsed = Math.ceil((highestMemoryLocationAccessed + WORD_SIZE) / WORD_SIZE); | ||
const linearMemoryCost = G_MEMORY * memoryWordsUsed; | ||
const quadraticMemoryCost = Math.floor((memoryWordsUsed * memoryWordsUsed) / G_QUAD_COEF); | ||
const memoryCost = linearMemoryCost + quadraticMemoryCost; | ||
logUtils.header('Memory breakdown', '-'); | ||
logUtils.table({ | ||
'memoryCost = linearMemoryCost + quadraticMemoryCost': memoryCost, | ||
linearMemoryCost, | ||
quadraticMemoryCost, | ||
highestMemoryLocationAccessed, | ||
memoryWordsUsed, | ||
}); | ||
return memoryCost; | ||
}, | ||
}; |
Oops, something went wrong.