Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active February 5, 2025 02:39
Show Gist options
  • Save xuwei-k/d3fda077d85ef70a643375777b2914a8 to your computer and use it in GitHub Desktop.
Save xuwei-k/d3fda077d85ef70a643375777b2914a8 to your computer and use it in GitHub Desktop.
profile scodec
libraryDependencies += "org.scodec" %% "scodec-bits" % "1.2.1"
libraryDependencies += "org.scodec" %% "scodec-core" % "2.3.2"
scalaVersion := "3.6.3"
run / fork := true
package example
import scodec.bits.*
import scodec.codecs.*
object Main {
val iterations = 1000000000
val str = "Hello World!"
val lengthBits = BitVector(str.length)
val stringBits = BitVector.encodeUtf8(str).toOption.get // Not safe, but only used for verification.
val bits = lengthBits ++ stringBits
def main(args: Array[String]): Unit = {
println("start")
for (i <- 0 until iterations) {
if((i % (iterations / 50)) == 0){
// show progress
println(i)
}
decodeByCodecs()
decodeBySplitAt()
}
println("end")
}
def decodeByCodecs(): String = {
(for
length <- uint8
str <- bytes(length)
yield new String(str.toArray, "UTF-8")).decode(bits).require.value
}
def decodeBySplitAt(): String = {
val (lengthBits, postLengthBits) = bits.splitAt(8)
val length = lengthBits.toInt(false)
val strBits = postLengthBits.take(length * 8L)
new String(strBits.toByteArray, "UTF-8")
}
}
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<style>
body {margin: 0; padding: 10px 10px 22px 10px; background-color: #ffffff}
h1 {margin: 5px 0 0 0; font-size: 18px; font-weight: normal; text-align: center}
header {margin: -24px 0 5px 0; line-height: 24px}
button {font: 12px sans-serif; cursor: pointer}
p {position: fixed; bottom: 0; margin: 0; padding: 2px 3px 2px 3px; outline: 1px solid #ffc000; display: none; overflow: hidden; white-space: nowrap; background-color: #ffffe0}
a {color: #0366d6}
#hl {position: absolute; display: none; overflow: hidden; white-space: nowrap; pointer-events: none; background-color: #ffffe0; outline: 1px solid #ffc000; height: 15px}
#hl span {padding: 0 3px 0 3px}
#status {left: 0}
#match {right: 0}
#reset {cursor: pointer}
#canvas {width: 100%; height: 464px}
</style>
</head>
<body style='font: 12px Verdana, sans-serif'>
<h1>CPU profile</h1>
<header style='text-align: left'><button id='reverse' title='Reverse'>&#x1f53b;</button>&nbsp;&nbsp;<button id='search' title='Search'>&#x1f50d;</button></header>
<header style='text-align: right'>Produced by <a href='https://github.com/async-profiler/async-profiler'>async-profiler</a></header>
<canvas id='canvas'></canvas>
<div id='hl'><span></span></div>
<p id='status'></p>
<p id='match'>Matched: <span id='matchval'></span> <span id='reset' title='Clear'>&#x274c;</span></p>
<script>
// Copyright The async-profiler authors
// SPDX-License-Identifier: Apache-2.0
'use strict';
let root, rootLevel, px, pattern;
let level0 = 0, left0 = 0, width0 = 0;
let reverse = false;
const levels = Array(29);
for (let h = 0; h < levels.length; h++) {
levels[h] = [];
}
const canvas = document.getElementById('canvas');
const c = canvas.getContext('2d');
const hl = document.getElementById('hl');
const status = document.getElementById('status');
const canvasWidth = canvas.offsetWidth;
const canvasHeight = canvas.offsetHeight;
canvas.style.width = canvasWidth + 'px';
canvas.width = canvasWidth * (devicePixelRatio || 1);
canvas.height = canvasHeight * (devicePixelRatio || 1);
if (devicePixelRatio) c.scale(devicePixelRatio, devicePixelRatio);
c.font = document.body.style.font;
const palette = [
[0xb2e1b2, 20, 20, 20],
[0x50e150, 30, 30, 30],
[0x50cccc, 30, 30, 30],
[0xe15a5a, 30, 40, 40],
[0xc8c83c, 30, 30, 10],
[0xe17d00, 30, 30, 0],
[0xcce880, 20, 20, 20],
];
function getColor(p) {
const v = Math.random();
return '#' + (p[0] + ((p[1] * v) << 16 | (p[2] * v) << 8 | (p[3] * v))).toString(16);
}
function f(key, level, left, width, inln, c1, int) {
levels[level0 = level].push({left: left0 += left, width: width0 = width || width0,
color: getColor(palette[key & 7]), title: cpool[key >>> 3],
details: (int ? ', int=' + int : '') + (c1 ? ', c1=' + c1 : '') + (inln ? ', inln=' + inln : '')
});
}
function u(key, width, inln, c1, int) {
f(key, level0 + 1, 0, width, inln, c1, int)
}
function n(key, width, inln, c1, int) {
f(key, level0, width0, width, inln, c1, int)
}
function samples(n) {
return n === 1 ? '1 sample' : n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' samples';
}
function pct(a, b) {
return a >= b ? '100' : (100 * a / b).toFixed(2);
}
function findFrame(frames, x) {
let left = 0;
let right = frames.length - 1;
while (left <= right) {
const mid = (left + right) >>> 1;
const f = frames[mid];
if (f.left > x) {
right = mid - 1;
} else if (f.left + f.width <= x) {
left = mid + 1;
} else {
return f;
}
}
if (frames[left] && (frames[left].left - x) * px < 0.5) return frames[left];
if (frames[right] && (x - (frames[right].left + frames[right].width)) * px < 0.5) return frames[right];
return null;
}
function search(r) {
if (r === true && (r = prompt('Enter regexp to search:', '')) === null) {
return;
}
pattern = r ? RegExp(r) : undefined;
const matched = render(root, rootLevel);
document.getElementById('matchval').textContent = pct(matched, root.width) + '%';
document.getElementById('match').style.display = r ? 'inline-block' : 'none';
}
function render(newRoot, newLevel) {
if (root) {
c.fillStyle = '#ffffff';
c.fillRect(0, 0, canvasWidth, canvasHeight);
}
root = newRoot || levels[0][0];
rootLevel = newLevel || 0;
px = canvasWidth / root.width;
const x0 = root.left;
const x1 = x0 + root.width;
const marked = [];
function mark(f) {
return marked[f.left] >= f.width || (marked[f.left] = f.width);
}
function totalMarked() {
let total = 0;
let left = 0;
Object.keys(marked).sort(function(a, b) { return a - b; }).forEach(function(x) {
if (+x >= left) {
total += marked[x];
left = +x + marked[x];
}
});
return total;
}
function drawFrame(f, y, alpha) {
if (f.left < x1 && f.left + f.width > x0) {
c.fillStyle = pattern && f.title.match(pattern) && mark(f) ? '#ee00ee' : f.color;
c.fillRect((f.left - x0) * px, y, f.width * px, 15);
if (f.width * px >= 21) {
const chars = Math.floor(f.width * px / 7);
const title = f.title.length <= chars ? f.title : f.title.substring(0, chars - 2) + '..';
c.fillStyle = '#000000';
c.fillText(title, Math.max(f.left - x0, 0) * px + 3, y + 12, f.width * px - 6);
}
if (alpha) {
c.fillStyle = 'rgba(255, 255, 255, 0.5)';
c.fillRect((f.left - x0) * px, y, f.width * px, 15);
}
}
}
for (let h = 0; h < levels.length; h++) {
const y = reverse ? h * 16 : canvasHeight - (h + 1) * 16;
const frames = levels[h];
for (let i = 0; i < frames.length; i++) {
drawFrame(frames[i], y, h < rootLevel);
}
}
return totalMarked();
}
function unpack(cpool) {
for (let i = 1; i < cpool.length; i++) {
cpool[i] = cpool[i - 1].substring(0, cpool[i].charCodeAt(0) - 32) + cpool[i].substring(1);
}
}
canvas.onmousemove = function() {
const h = Math.floor((reverse ? event.offsetY : (canvasHeight - event.offsetY)) / 16);
if (h >= 0 && h < levels.length) {
const f = findFrame(levels[h], event.offsetX / px + root.left);
if (f) {
if (f !== root) getSelection().removeAllRanges();
hl.style.left = (Math.max(f.left - root.left, 0) * px + canvas.offsetLeft) + 'px';
hl.style.width = (Math.min(f.width, root.width) * px) + 'px';
hl.style.top = ((reverse ? h * 16 : canvasHeight - (h + 1) * 16) + canvas.offsetTop) + 'px';
hl.firstChild.textContent = f.title;
hl.style.display = 'block';
canvas.title = f.title + '\n(' + samples(f.width) + f.details + ', ' + pct(f.width, levels[0][0].width) + '%)';
canvas.style.cursor = 'pointer';
canvas.onclick = function() {
if (f !== root) {
render(f, h);
canvas.onmousemove();
}
};
status.textContent = 'Function: ' + canvas.title;
status.style.display = 'inline-block';
return;
}
}
canvas.onmouseout();
}
canvas.onmouseout = function() {
hl.style.display = 'none';
status.style.display = 'none';
canvas.title = '';
canvas.style.cursor = '';
canvas.onclick = null;
}
canvas.ondblclick = function() {
getSelection().selectAllChildren(hl);
}
document.getElementById('reverse').onclick = function() {
reverse = !reverse;
render();
}
document.getElementById('search').onclick = function() {
search(true);
}
document.getElementById('reset').onclick = function() {
search(false);
}
window.onkeydown = function() {
if (event.ctrlKey && event.keyCode === 70) {
event.preventDefault();
search(true);
} else if (event.keyCode === 27) {
search(false);
}
}
const cpool = [
'all',
' Agent_OnAttach',
'!llocateHeap',
' CompositeElapsedCounterSource::now',
'"ncurrentGCThread::run',
' G1AllocRegion::new_alloc_region_and_allocate',
'"BatchedTask::work',
'"CollectedHeap::attempt_allocation',
'1do_collection_pause_at_safepoint',
'Q_helper',
'1par_iterate_regions_array',
'1rebuild_free_region_list',
'"EvacPhaseWithTrimTimeTracker::G1EvacPhaseWithTrimTimeTracker',
'@~G1EvacPhaseWithTrimTimeTracker',
'&uateRegionsBaseTask::work',
'1Task::evacuate_live_objects',
'"ParEvacuateFollowersClosure::do_void',
'?offer_termination',
'#repareEvacuationTask::work',
'"RemSet::merge_heap_roots',
'*scan_collection_set_regions',
'(ScanState::prepare',
'"ScanCollectionSetRegionClosure::do_heap_region',
'#erviceThread::run_service',
'1schedule',
'1wait_for_task',
'"YoungCollector::collect',
'2evacuate_initial_collection_set',
'2post_evacuate_collection_set',
'3re_evacuate_collection_set',
' HeapRegionManager::rebuild_free_list',
' InstanceKlass::allocate_instance',
' JavaThread::thread_main_inner',
'!vmtiAgent::load',
'*List::load_agent',
' MemAllocator::allocate',
'.mem_allocate_inside_tlab_slow',
'!onitor::wait_without_safepoint_check',
'!utex::lock_without_safepoint_check',
' OptoRuntime::new_instance_C',
' PlatformMonitor::wait',
'!rofiler::run',
' SpinPause',
' TaskTerminator::offer_termination',
'!hread::call_run',
' VMThread::evaluate_operation',
'*inner_execute',
'*run',
'*wait_for_operation',
'"_G1CollectForAllocation::doit',
'#Operation::evaluate',
' WorkerThread::run',
',s::run_task',
' [unknown_Java]',
' __psynch_cvbroad',
'+signal',
'+wait',
')mutexwait',
'!new_array_Java',
'%instance_Java',
'!platform_memset',
'"thread_cond_wait',
')mutex_firstfit_lock_slow',
')start',
' arrayof_jlong_disjoint_arraycopy',
'!ttach_listener_thread_entry',
' example/Main$$$Lambda.0x00000005010b9820.apply',
'Ccf980.apply',
'Cd02b0.apply',
'-.decodeByCodecs',
'<$$anonfun$1',
'G$$anonfun$1',
'Fadapted$1',
'6SplitAt',
'.main',
'2$$anonfun$1',
'<adapted$1',
',.main',
' java/lang/Integer.valueOf',
'*Object.<init>',
'*String.<init>',
'*invoke/DirectMethodHandle$Holder.newInvokeSpecial',
'C.allocateInstance',
'1Invokers$Holder.linkToTargetMethod',
'%util/Arrays.copyOfRange',
'<Byte',
'!byte_arraycopy',
'&disjoint_arraycopy',
' load_agent',
' mach_absolute_time',
' os::elapsed_counter',
'$javaTimeNanos',
'$malloc',
' pthread_jit_write_protect_np',
' scala/collection/immutable/$colon$colon.<init>',
';List.$colon$colon',
'@<init>',
'@equals',
'@listEq$1',
';Range.foreach',
'&math/Ordered.$init$',
'&runtime/BoxesRunTime.unboxToInt',
'.Statics.releaseFence',
'.function/JProcedure1.apply',
'"odec/Attempt$.successful',
'/Successful$.apply',
'9.<init>',
':flatMap',
':map',
'..<init>',
'\'Codec$$anon$1.<init>',
'5decode',
'38.decode',
'-given_Transform_Codec$.exmap',
'Dxmap',
',.exmap',
'2$',
'\'DecodeResult$.apply',
'3.<init>',
'4map',
'-r$$anon$1$$Lambda.0x00000005010d1698.apply',
'6.decode',
'=$$anonfun$1',
'52$$Lambda.0x00000005010cac78.apply',
'6.decode',
'=$$anonfun$2',
'53$$Lambda.0x00000005010d0f08.apply',
'M12d0.apply',
'6.decode',
'=$$anonfun$3',
'..scodec$Decoder$$anon$3$$_$decode$$anonfun$3$$anonfun$1',
'\'Transform$$Lambda.0x00000005010bd000.apply',
'0.xmap',
'5$',
'6$anonfun$1',
'\'bits/BitVector$.toBytes',
'6Bytes$.apply',
';.<init>',
'<take',
'5.<init>',
'6bytes',
'6compact',
'6toByteArray',
'<Vector',
'-yteVector.copyToArray',
'7foreachV',
'7go$4',
'7toArray',
'\'codecs/FixedSizeCodec.decode',
'.codecs$package$$$Lambda.0x00000005010cb788.apply',
'>anon$7.decode',
'Eexmap',
'=.$anonfun$3',
'>bytes',
'!emaphore_signal',
'0_trap',
'*wait_trap',
'!mall_malloc_from_free_list',
'-should_clear',
'!td::__1::basic_ostream<char, std::__1::char_traits<char>>& std::__1::__put_character_sequence[abi:v160006]<char, std::__1::char_traits<char>>',
'!zone_malloc_should_clear',
' thread_native_entry',
'\'start'
];
unpack(cpool);
n(3,1542)
u(427,3)
u(467,1)
u(747)
f(475,2,1,2)
u(747)
f(617,1,2,1496)
u(593)
u(529,6)
u(610)
u(810)
f(793,3,6,1490)
f(529,4,25,1434)
f(609,5,6,1428,8,0,0)
f(601,6,8,1412)
f(553,7,17,944)
f(994,8,15,929,495,0,0)
u(858,929,495,0,0)
u(986,929,495,0,0)
u(1002,929,495,0,0)
u(538,268,219,0,0)
u(578,268,219,0,0)
u(562,268,219,0,0)
u(1226,268,219,0,0)
u(914,268,219,0,0)
u(1066,268,219,0,0)
u(1058,268,219,0,0)
u(665,24)
u(649)
u(657)
u(641)
f(906,19,24,244,219,0,0)
u(906,244,219,0,0)
u(1210,244,219,0,0)
u(930,244,219,0,0)
u(922,244,219,0,0)
f(881,24,219,25)
f(970,12,25,661,276,0,0)
u(866,435,184,0,0)
u(962,435,184,0,0)
u(978,435,184,0,0)
u(954,435,184,0,0)
u(546,435,184,0,0)
u(570,435,184,0,0)
u(641,152,49,0,0)
f(641,20,49,94)
u(674)
u(682)
f(515,23,74,20)
f(785,20,20,9)
f(1178,19,9,283,135,0,0)
u(1154,283,135,0,0)
u(1162,283,135,0,0)
u(762,145,99,0,0)
u(316,2)
u(252)
u(284)
u(292)
u(60,1)
u(44)
f(483,27,1)
f(754,23,1,143,99,0,0)
f(633,24,99,28)
n(769,16)
f(1169,22,16,138,36,0,0)
u(778,25)
n(825,113,11,0,0)
f(817,24,37,13)
n(825,63)
f(699,25,57,6)
f(898,13,6,226,92,0,0)
u(890,226,92,0,0)
u(1026,226,92,0,0)
u(857,156,48,0,0)
u(1009,156,48,0,0)
u(1033,156,48,0,0)
u(866,40,14,0,0)
u(1018,40,14,0,0)
u(1042,40,14,0,0)
u(938,40,14,0,0)
u(946,40,14,0,0)
f(873,24,14,26)
f(1049,19,26,116,34,0,0)
u(1073,116,34,0,0)
u(834,26,13,0,0)
u(842,26,13,0,0)
u(850,26,13,0,0)
f(1145,24,13,13)
f(1193,21,13,90,21,0,0)
u(1217,90,21,0,0)
u(1121,90,21,0,0)
f(801,24,21,18)
n(1129,10)
n(1145,41)
f(1129,25,24,17)
f(1202,16,17,70,44,0,0)
u(1186,70,44,0,0)
u(1106,70,44,0,0)
u(1106,70,44,0,0)
u(1082,70,44,0,0)
u(1090,70,44,0,0)
u(1098,70,44,0,0)
u(1114,70,44,0,0)
f(633,24,44,12)
n(881,14)
f(585,7,14,451)
f(642,8,10,162,60,0,0)
f(641,9,69,93)
u(674)
u(682)
f(515,12,80,13)
f(1138,8,13,279,253,0,0)
u(1146,158,144,0,0)
f(1129,10,144,14)
f(1178,9,14,121,109,0,0)
u(316,1)
u(252)
u(284)
u(292)
u(483)
f(1154,10,1,120,109,0,0)
u(1162,120,109,0,0)
u(1170,120,109,0,0)
f(691,13,94,3)
n(699,12)
n(1129,11)
f(809,6,11,8)
u(601)
f(585,4,8,5)
n(601,17)
n(626,9)
f(1299,1,9,43)
u(507)
u(1292)
u(356)
u(36,1)
u(188)
u(204)
u(300)
u(324)
u(451)
f(260,5,1)
u(524)
u(708)
u(276)
u(268)
u(11)
u(332)
u(1276)
f(380,5,1,7)
u(372,6)
u(364)
u(404)
u(396)
u(68)
u(76)
u(212)
u(220,2)
u(156,1)
u(420)
u(1243)
f(420,14,1)
u(1243)
f(228,13,1,2)
u(92,1)
u(244)
u(420)
u(1243)
f(196,14,1)
u(443)
f(236,13,1,2)
u(172,1)
u(20)
u(740)
u(1283)
u(1267)
u(1259)
f(420,14,1)
u(1235)
f(388,6,1)
u(435)
f(412,5,1,34)
u(52,1)
u(483)
f(116,6,1,22)
u(124,12)
u(132)
u(140)
u(348)
u(300,7)
u(324)
u(451,6)
n(491,1)
u(499)
u(459)
f(308,11,1,4)
u(499)
u(459)
f(339,11,4,1)
f(164,7,1,10)
u(84)
u(180)
u(100,6)
u(28)
u(724)
u(715,1)
n(732,5)
f(108,10,5,4)
u(28)
u(724)
u(715,1)
n(732,3)
f(148,6,3,1)
u(308)
u(499)
u(459)
f(1243,6,1)
n(1251,9)
search();
</script></body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment