From fe8d9f559143235842ccaef9a3850e7aadc1bfdc Mon Sep 17 00:00:00 2001 From: akvlad Date: Mon, 12 Feb 2024 12:50:21 +0200 Subject: [PATCH 01/12] profile improvements scripts --- lib/db/maintain/scripts.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/db/maintain/scripts.js b/lib/db/maintain/scripts.js index ad0b4dd3..520428f8 100644 --- a/lib/db/maintain/scripts.js +++ b/lib/db/maintain/scripts.js @@ -390,7 +390,39 @@ module.exports.profiles = [ key, val, cityHash64(val) % 50000 as val_id - FROM profiles_series_gin` + FROM profiles_series_gin`, + + `ALTER TABLE profiles_input {{{OnCluster}}} + ADD COLUMN IF NOT EXISTS \`tree\` Array(Tuple(UInt64, UInt64, UInt64, Array(Tuple(String, Int64, Int64)))), + ADD COLUMN IF NOT EXISTS \`functions\` Array(Tuple(UInt64, String))`, + + `ALTER TABLE profiles {{{OnCluster}}} + ADD COLUMN IF NOT EXISTS \`tree\` Array(Tuple(UInt64, UInt64, UInt64, Array(Tuple(String, Int64, Int64)))), + ADD COLUMN IF NOT EXISTS \`functions\` Array(Tuple(UInt64, String))`, + + 'RENAME TABLE IF EXISTS profiles_mv {{{OnCluster}}} TO profiles_mv_bak', + + `CREATE MATERIALIZED VIEW IF NOT EXISTS profiles_mv {{{OnCluster}}} TO profiles AS + SELECT + timestamp_ns, + cityHash64(arraySort(arrayConcat( + profiles_input.tags, [ + ('__type__', concatWithSeparator(':', type, period_type, period_unit) as _type_id), + ('__sample_types_units__', arrayStringConcat(arrayMap(x -> x.1 || ':' || x.2, arraySort(sample_types_units)), ';')), + ('service_name', service_name) + ])) as _tags) as fingerprint, + _type_id as type_id, + sample_types_units, + service_name, + duration_ns, + payload_type, + payload, + values_agg, + tree, + functions + FROM profiles_input`, + + 'DROP TABLE IF EXISTS profiles_mv_bak {{{OnCluster}}}' ] module.exports.profiles_dist = [ From c2894103255667185c7a47aa9dece6f7269d9f9d Mon Sep 17 00:00:00 2001 From: akvlad Date: Mon, 12 Feb 2024 20:15:14 +0200 Subject: [PATCH 02/12] profile improvements impl --- pyroscope/pprof-bin/pkg/pprof_bin.d.ts | 5 + pyroscope/pprof-bin/pkg/pprof_bin.js | 20 +++ pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 73426 -> 83701 bytes .../pprof-bin/pkg/pprof_bin_bg.wasm.d.ts | 1 + pyroscope/pprof-bin/src/lib.rs | 161 +++++++++++++++++- pyroscope/pyroscope.js | 117 +++++++++++++ 6 files changed, 302 insertions(+), 2 deletions(-) diff --git a/pyroscope/pprof-bin/pkg/pprof_bin.d.ts b/pyroscope/pprof-bin/pkg/pprof_bin.d.ts index f9cc13cc..fb8be1fa 100644 --- a/pyroscope/pprof-bin/pkg/pprof_bin.d.ts +++ b/pyroscope/pprof-bin/pkg/pprof_bin.d.ts @@ -13,6 +13,11 @@ export function merge_tree(id: number, bytes: Uint8Array, sample_type: string): */ export function export_tree(id: number, sample_type: string): Uint8Array; /** +* @param {Uint8Array} bytes +* @returns {Uint8Array} +*/ +export function tree2Bin(bytes: Uint8Array): Uint8Array; +/** * @param {number} id */ export function drop_tree(id: number): void; diff --git a/pyroscope/pprof-bin/pkg/pprof_bin.js b/pyroscope/pprof-bin/pkg/pprof_bin.js index 0d27eae1..bb57be49 100644 --- a/pyroscope/pprof-bin/pkg/pprof_bin.js +++ b/pyroscope/pprof-bin/pkg/pprof_bin.js @@ -140,6 +140,26 @@ module.exports.export_tree = function(id, sample_type) { } }; +/** +* @param {Uint8Array} bytes +* @returns {Uint8Array} +*/ +module.exports.tree2Bin = function(bytes) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + wasm.tree2Bin(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var v2 = getArrayU8FromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1, 1); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +}; + /** * @param {number} id */ diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index 04fee2a8ab67b0a7104c0a01c79fcc140c50a239..a12eeb4ef6e17749f2e9fdee88419d6b3d99c5ea 100644 GIT binary patch literal 83701 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 delta 32151 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 OoEOGD`P+VzN&YVl)oiW+ diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts index e2fcf635..e5ed0a30 100644 --- a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts +++ b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts @@ -3,6 +3,7 @@ export const memory: WebAssembly.Memory; export function merge_tree(a: number, b: number, c: number, d: number, e: number): void; export function export_tree(a: number, b: number, c: number, d: number): void; +export function tree2Bin(a: number, b: number, c: number): void; export function drop_tree(a: number): void; export function init_panic_hook(): void; export function __wbindgen_malloc(a: number, b: number): number; diff --git a/pyroscope/pprof-bin/src/lib.rs b/pyroscope/pprof-bin/src/lib.rs index 4d03363d..15d5d74a 100644 --- a/pyroscope/pprof-bin/src/lib.rs +++ b/pyroscope/pprof-bin/src/lib.rs @@ -130,7 +130,7 @@ unsafe fn merge(tree: &mut Tree, p: &Profile) { } } -/*fn read_uleb128(bytes: &[u8]) -> (usize, usize) { +fn read_uleb128(bytes: &[u8]) -> (usize, usize) { let mut result = 0; let mut shift = 0; loop { @@ -142,7 +142,15 @@ unsafe fn merge(tree: &mut Tree, p: &Profile) { } } (result, shift) -}*/ +} + +fn read_uint64(bytes: &[u8]) -> (u64) { + let mut res: u64 = 0; + for i in 0..8 { + res |= (bytes[i] as u64) << (i * 8); + } + res +} static mut INTS: [i64; 4000000] = [0; 4000000]; @@ -262,6 +270,138 @@ pub unsafe fn export_tree(id: u32, sample_type: String) -> Vec { res.encode_to_vec() } +struct TreeNodeV2 { + parent_id: u64, + fn_id: u64, + node_id: u64, + slf: u64, + total: u64 +} + +#[wasm_bindgen] +pub fn tree2Bin(bytes: &[u8]) -> Vec { + let mut funcs: HashMap = HashMap::new(); + let mut funcsArr: Vec = vec!["total".to_string()]; + let mut size = 0; + let mut offs = 0; + let mut max_self: u64 = 0; + (size, offs) = read_uleb128(bytes); + for i in 0..size { + let id = read_uint64(&bytes[offs..]); + offs += 8; + let mut _offs: usize = 0; + let mut _size: usize = 0; + (_size, _offs) = read_uleb128(&bytes[offs..]); + offs += _offs; + funcsArr.push(String::from_utf8_lossy(&bytes[offs..offs + _size]).to_string()); + funcs.insert(id, funcsArr.len() - 1); + offs += _size; + } + + let mut trie: HashMap> = HashMap::new(); + let mut _offs: usize = 0; + (size, _offs) = read_uleb128(&bytes[offs..]); + offs += _offs; + for _i in 0..size { + let parent_id = read_uint64(&bytes[offs..]); + offs += 8; + let fn_id = read_uint64(&bytes[offs..]); + offs += 8; + let node_id = read_uint64(&bytes[offs..]); + offs += 8; + let slf = read_uint64(&bytes[offs..]); + offs += 8; + let total = read_uint64(&bytes[offs..]); + if max_self < slf { + max_self = slf; + } + offs += 8; + if trie.contains_key(&parent_id) { + trie.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + fn_id, + parent_id, + node_id, + slf, + total + }) + } else { + trie.insert(parent_id, Vec::new()); + trie.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + fn_id, + parent_id, + node_id, + slf, + total + }); + } + } + + let mut total: u64 = 0; + for i in trie.get(&(0u64)).unwrap().iter() { + total += i.total; + } + + let mut res = SelectMergeStacktracesResponse::default(); + let mut fg = FlameGraph::default(); + fg.names = funcsArr.clone(); + let mut lvl = Level::default(); + lvl.values.extend([0, total as i64, 0, 0]); + fg.levels.push(lvl); + + let totalNode: TreeNodeV2 = TreeNodeV2 { + slf: 0, + total: total, + node_id: 0, + fn_id: 0, + parent_id: 0 + }; + + let mut prepend_map: HashMap = HashMap::new(); + + let mut refs: Vec<&TreeNodeV2> = vec![&totalNode]; + let mut refLen: usize = 1; + while refLen > 0 { + let mut prepend: u64 = 0; + let _refs = refs.clone(); + refs.clear(); + lvl = Level::default(); + for parent in _refs.iter() { + prepend += prepend_map.get(&parent.node_id).unwrap_or(&0); + let opt = trie.get(&parent.node_id); + + if opt.is_none() { + prepend += parent.total; + continue; + } + let mut totalSum: u64 = 0; + for n in opt.unwrap().iter() { + let current_prepend = (prepend_map.get(&n.node_id).unwrap_or(&0u64) + prepend); + prepend = 0; + prepend_map.insert(n.node_id, current_prepend); + refs.push(n); + totalSum += n.total; + lvl.values.extend( + [ + current_prepend as i64, + n.total as i64, + n.slf as i64, + funcs[&n.fn_id] as i64 + ] + ); + + } + prepend = parent.slf; + + } + fg.levels.push(lvl.clone()); + refLen = refs.len(); + } + fg.total = totalNode.total as i64; + fg.max_self = max_self as i64; + res.flamegraph = Some(fg); + res.encode_to_vec() +} + #[wasm_bindgen] pub unsafe fn drop_tree(id: u32) { let mut ctx = CTX.lock().unwrap(); @@ -274,3 +414,20 @@ pub unsafe fn drop_tree(id: u32) { pub fn init_panic_hook() { console_error_panic_hook::set_once(); } + + +#[cfg(test)] +mod tests { + use std::fs::File; + use std::io::Read; + use web_sys::console::assert; + use crate::tree2Bin; + + #[test] + fn it_works() { + let mut file = File::open("/home/hromozeka/QXIP/qryn/test.dat"); + let mut contents = Vec::new(); + file.unwrap().read_to_end(&mut contents); + tree2Bin(contents.as_slice()); + } +} diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index d6debca4..64dfc150 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -168,6 +168,7 @@ const labelSelectorQuery = (query, labelSelector) => { } const selectMergeStacktraces = async (req, res) => { + return await selectMergeStacktracesV2(req, res) const dist = clusterName ? '_dist' : '' const typeRegex = parseTypeId(req.body.getProfileTypeid()) const sel = req.body.getLabelSelector() @@ -246,6 +247,122 @@ const selectMergeStacktraces = async (req, res) => { return res.code(200).send(Buffer.from(sResp)) } +const selectMergeStacktracesV2 = async (req, res) => { + + const dist = clusterName ? '_dist' : '' + const typeRegex = parseTypeId(req.body.getProfileTypeid()) + const sel = req.body.getLabelSelector() + const fromTimeSec = req.body && req.body.getStart() + ? Math.floor(parseInt(req.body.getStart()) / 1000) + : Math.floor((Date.now() - 1000 * 60 * 60 * 48) / 1000) + const toTimeSec = req.body && req.body.getEnd() + ? Math.floor(parseInt(req.body.getEnd()) / 1000) + : Math.floor(Date.now() / 1000) + const idxSelect = (new Sql.Select()) + .select('fingerprint') + .from(`${DATABASE_NAME()}.profiles_series_gin`) + .where( + Sql.And( + Sql.Eq(new Sql.Raw(`has(sample_types_units, (${Sql.quoteVal(typeRegex.sampleType)},${Sql.quoteVal(typeRegex.sampleUnit)}))`), 1), + Sql.Eq('type_id', Sql.val(`${typeRegex.type}:${typeRegex.periodType}:${typeRegex.periodUnit}`)), + Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)), + Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)) + ) + ).groupBy('fingerprint') + labelSelectorQuery(idxSelect, sel) + const rawReq = (new Sql.Select()) + .select([ + new Sql.Raw(`arrayMap(x -> (x.1, x.2, x.3, (arrayFirst(y -> y.1 == ${Sql.quoteVal(`${typeRegex.sampleType}:${typeRegex.sampleUnit}`)}, x.4) as af).2, af.3), tree)`), + 'tree' + ], 'functions') + .from(`${DATABASE_NAME()}.profiles${dist}`) + .where( + Sql.And( + Sql.Gte('timestamp_ns', new Sql.Raw(Math.floor(fromTimeSec) + '000000000')), + Sql.Lte('timestamp_ns', new Sql.Raw(Math.floor(toTimeSec) + '000000000')), + new Sql.In('fingerprint', 'IN', idxSelect) + )) + if (process.env.ADVANCED_PROFILES_MERGE_LIMIT) { + rawReq.orderBy(['timestamp_ns', 'desc']).limit(parseInt(process.env.ADVANCED_PROFILES_MERGE_LIMIT)) + } + const withRawReq = new Sql.With('raw', rawReq, !!clusterName) + const joinedReq = (new Sql.Select()).with(withRawReq).select([ + new Sql.Raw('(raw.tree.1, raw.tree.2, raw.tree.3, sum(raw.tree.4), sum(raw.tree.5))'), + 'tree2' + ]).from(new Sql.WithReference(withRawReq)) + .join('raw.tree', 'array') + .groupBy(new Sql.Raw('raw.tree.1'), new Sql.Raw('raw.tree.2'), new Sql.Raw('raw.tree.3')) + const withJoinedReq = new Sql.With('joined', joinedReq, !!clusterName) + const joinedAggregatedReq = (new Sql.Select()).select( + [new Sql.Raw('groupArray(tree2)'), 'tree']).from(new Sql.WithReference(withJoinedReq)) + //const withJoinedAggregatedReq = new Sql.With('joinedAggregated', joinedAggregatedReq, !!clusterName) + const functionsReq = (new Sql.Select()).select( + [new Sql.Raw('groupUniqArray(raw.functions)'), 'functions2'] + ).from(new Sql.WithReference(withRawReq)).join('raw.functions', 'array') + //const withFunctionsReq = new Sql.With('functions', functionsReq, !!clusterName) + + const brack1 = new Sql.Raw(`(${joinedAggregatedReq.toString()})`) + const brack2 = new Sql.Raw(`(${functionsReq.toString()})`) + + const sqlReq = (new Sql.Select()) + .with(withJoinedReq, withRawReq) + .select( + [brack2, 'functions'], + [brack1, 'tree'] + ) + + let start = Date.now() + console.log(sqlReq.toString()) + const profiles = await clickhouse.rawRequest(sqlReq.toString() + ' FORMAT RowBinary', + null, + DATABASE_NAME(), + { + responseType: 'arraybuffer' + }) + const binData = Uint8Array.from(profiles.data) + require('fs').writeFileSync('test.dat', binData) + req.log.debug(`selectMergeStacktraces: profiles downloaded: ${binData.length / 1025}kB in ${Date.now() - start}ms`) + //start = Date.now() + require('./pprof-bin/pkg/pprof_bin').init_panic_hook() + start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 + const resp = pprofBin.tree2Bin(binData) + const exportTreeLat = (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start + req.log.debug(`export_tree: ${exportTreeLat / BigInt(1000000)}ms`) + return res.code(200).send(Buffer.from(resp)) + /*const promises = [] + const _ctxIdx = ++ctxIdx + let mergeTreeLat = BigInt(0) + let exportTreeLat = BigInt(0) + for (let i = 0; i < binData.length;) { + const [size, shift] = readULeb32(binData, i) + const uarray = Uint8Array.from(profiles.data.slice(i + shift, i + size + shift)) + i += size + shift + promises.push(new Promise((resolve, reject) => setTimeout(() => { + try { + const start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 + pprofBin.merge_tree(_ctxIdx, uarray, `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) + mergeTreeLat += (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start + resolve() + } catch (e) { + reject(e) + } + }, 0))) + } + let sResp = null + try { + await Promise.all(promises) + const start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 + sResp = pprofBin.export_tree(_ctxIdx, `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) + exportTreeLat += (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start + } finally { + req.log.debug(`selectMergeStacktraces: profiles processed: ${promises.length} in ${Date.now() - start}ms`) + req.log.debug(`selectMergeStacktraces: mergeTree: ${mergeTreeLat / BigInt(1000000)}ms`) + req.log.debug(`selectMergeStacktraces: export_tree: ${exportTreeLat / BigInt(1000000)}ms`) + try { pprofBin.drop_tree(_ctxIdx) } catch (e) { req.log.error(e) } + } + return res.code(200).send(Buffer.from(sResp))*/ +} + const selectSeries = async (req, res) => { const _req = req.body const fromTimeSec = Math.floor(req.getStart && req.getStart() From 5f84c5fa5b033687e04d034828902b235d06adbf Mon Sep 17 00:00:00 2001 From: akvlad Date: Tue, 13 Feb 2024 13:17:09 +0200 Subject: [PATCH 03/12] drop unused parts --- pyroscope/pprof-bin/src/lib.rs | 17 ---------------- pyroscope/pyroscope.js | 36 ---------------------------------- 2 files changed, 53 deletions(-) diff --git a/pyroscope/pprof-bin/src/lib.rs b/pyroscope/pprof-bin/src/lib.rs index 15d5d74a..1b419d30 100644 --- a/pyroscope/pprof-bin/src/lib.rs +++ b/pyroscope/pprof-bin/src/lib.rs @@ -414,20 +414,3 @@ pub unsafe fn drop_tree(id: u32) { pub fn init_panic_hook() { console_error_panic_hook::set_once(); } - - -#[cfg(test)] -mod tests { - use std::fs::File; - use std::io::Read; - use web_sys::console::assert; - use crate::tree2Bin; - - #[test] - fn it_works() { - let mut file = File::open("/home/hromozeka/QXIP/qryn/test.dat"); - let mut contents = Vec::new(); - file.unwrap().read_to_end(&mut contents); - tree2Bin(contents.as_slice()); - } -} diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index 64dfc150..14fe69f8 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -295,11 +295,9 @@ const selectMergeStacktracesV2 = async (req, res) => { const withJoinedReq = new Sql.With('joined', joinedReq, !!clusterName) const joinedAggregatedReq = (new Sql.Select()).select( [new Sql.Raw('groupArray(tree2)'), 'tree']).from(new Sql.WithReference(withJoinedReq)) - //const withJoinedAggregatedReq = new Sql.With('joinedAggregated', joinedAggregatedReq, !!clusterName) const functionsReq = (new Sql.Select()).select( [new Sql.Raw('groupUniqArray(raw.functions)'), 'functions2'] ).from(new Sql.WithReference(withRawReq)).join('raw.functions', 'array') - //const withFunctionsReq = new Sql.With('functions', functionsReq, !!clusterName) const brack1 = new Sql.Raw(`(${joinedAggregatedReq.toString()})`) const brack2 = new Sql.Raw(`(${functionsReq.toString()})`) @@ -320,47 +318,13 @@ const selectMergeStacktracesV2 = async (req, res) => { responseType: 'arraybuffer' }) const binData = Uint8Array.from(profiles.data) - require('fs').writeFileSync('test.dat', binData) req.log.debug(`selectMergeStacktraces: profiles downloaded: ${binData.length / 1025}kB in ${Date.now() - start}ms`) - //start = Date.now() require('./pprof-bin/pkg/pprof_bin').init_panic_hook() start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 const resp = pprofBin.tree2Bin(binData) const exportTreeLat = (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start req.log.debug(`export_tree: ${exportTreeLat / BigInt(1000000)}ms`) return res.code(200).send(Buffer.from(resp)) - /*const promises = [] - const _ctxIdx = ++ctxIdx - let mergeTreeLat = BigInt(0) - let exportTreeLat = BigInt(0) - for (let i = 0; i < binData.length;) { - const [size, shift] = readULeb32(binData, i) - const uarray = Uint8Array.from(profiles.data.slice(i + shift, i + size + shift)) - i += size + shift - promises.push(new Promise((resolve, reject) => setTimeout(() => { - try { - const start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 - pprofBin.merge_tree(_ctxIdx, uarray, `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) - mergeTreeLat += (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start - resolve() - } catch (e) { - reject(e) - } - }, 0))) - } - let sResp = null - try { - await Promise.all(promises) - const start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 - sResp = pprofBin.export_tree(_ctxIdx, `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) - exportTreeLat += (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start - } finally { - req.log.debug(`selectMergeStacktraces: profiles processed: ${promises.length} in ${Date.now() - start}ms`) - req.log.debug(`selectMergeStacktraces: mergeTree: ${mergeTreeLat / BigInt(1000000)}ms`) - req.log.debug(`selectMergeStacktraces: export_tree: ${exportTreeLat / BigInt(1000000)}ms`) - try { pprofBin.drop_tree(_ctxIdx) } catch (e) { req.log.error(e) } - } - return res.code(200).send(Buffer.from(sResp))*/ } const selectSeries = async (req, res) => { From d3c8aa583cce2386fc1f17c8eaf4b3100205aeed Mon Sep 17 00:00:00 2001 From: akvlad Date: Tue, 13 Feb 2024 16:06:25 +0200 Subject: [PATCH 04/12] impl new trie format --- pyroscope/pprof-bin/Cargo.toml | 1 + pyroscope/pprof-bin/src/lib.rs | 360 +++++++++++++-------------------- 2 files changed, 144 insertions(+), 217 deletions(-) diff --git a/pyroscope/pprof-bin/Cargo.toml b/pyroscope/pprof-bin/Cargo.toml index 07b59dcb..25db2941 100644 --- a/pyroscope/pprof-bin/Cargo.toml +++ b/pyroscope/pprof-bin/Cargo.toml @@ -17,6 +17,7 @@ bytes = "1.5.0" prost = "0.12.3" json = "0.12.4" lazy_static = "1.4.0" +cityhash = "0.1.0" # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires diff --git a/pyroscope/pprof-bin/src/lib.rs b/pyroscope/pprof-bin/src/lib.rs index 1b419d30..10e5eb22 100644 --- a/pyroscope/pprof-bin/src/lib.rs +++ b/pyroscope/pprof-bin/src/lib.rs @@ -13,6 +13,7 @@ use std::collections::HashMap; use std::sync::Mutex; use std::vec::Vec; use wasm_bindgen::prelude::*; +use cityhash::cityhash_1::city_hash_64; pub mod pprof_pb { @@ -33,34 +34,32 @@ pub mod pprof_pb { } } -struct TreeNode { - name_idx: usize, - prepend: i64, - total: i64, - _self: i64, - children: Vec, -} - -impl TreeNode { - fn append_child(&mut self, _name_idx: usize) { - self.children.push(TreeNode { - name_idx: _name_idx, - prepend: 0, - total: 0, - _self: 0, - children: Vec::new(), - }); - } +struct TreeNodeV2 { + parent_id: u64, + fn_id: u64, + node_id: u64, + slf: u64, + total: u64 } struct Tree { names: Vec, - names_map: HashMap, - root: TreeNode, + names_map: HashMap, + nodes: HashMap>, sample_type: String, max_self: i64, } +fn hash_128_to_64(l: u64, h: u64) -> u64 { + let kMul: u64 = 0x9ddfea08eb382d69; + let mut a = (l ^ h) * kMul; + a ^= (a >> 47); + let mut b = (h ^ a) * kMul; + b ^= (b >> 47); + b *= kMul; + b +} + unsafe fn merge(tree: &mut Tree, p: &Profile) { let mut functions: HashMap = HashMap::new(); for f in p.function.iter() { @@ -87,47 +86,45 @@ unsafe fn merge(tree: &mut Tree, p: &Profile) { if value_idx == -1 { return; } - for i in 0..p.location.len() { - let l = &p.location[i]; + let u_value_idx = value_idx as usize; + for l in p.location.iter() { let line = &p.string_table[functions[&l.line[0].function_id].name as usize]; - if tree.names_map.contains_key(line) { + let line_hash = city_hash_64(line.as_bytes()); + if tree.names_map.contains_key(&line_hash) { continue; } tree.names.push(line.clone()); - tree.names_map.insert(line.clone(), tree.names.len() - 1); + tree.names_map.insert(line_hash, tree.names.len() - 1); } for s in p.sample.iter() { - let mut node = &mut tree.root; + let mut parent_id: u64 = 0; for i in (0..s.location_id.len()).rev() { let location = locations[&s.location_id[i]]; - let name_idx = tree.names_map - [&p.string_table[functions[&location.line[0].function_id].name as usize]]; - let mut node_idx: i32 = -1; - for j in 0..node.children.len() { - if node.children[j].name_idx == name_idx { - node_idx = j as i32; - break; - } + let name_hash = city_hash_64( + p.string_table[functions[&location.line[0].function_id].name as usize].as_bytes() + ); + let node_id = hash_128_to_64(parent_id, name_hash); + if !tree.nodes.contains_key(&parent_id) { + tree.nodes.insert(parent_id, Vec::new()); } - if node_idx == -1 { - node.append_child(name_idx); - node_idx = (node.children.len() as i32) - 1; - } - node = &mut node.children[node_idx as usize]; - node.total += s.value[value_idx as usize]; + let mut slf: u64 = 0; if i == 0 { - node._self += s.value[value_idx as usize]; - if node._self > tree.max_self { - tree.max_self = node._self - } + slf = s.value[u_value_idx] as u64; + } + if tree.max_self < slf as i64 { + tree.max_self = slf as i64; } + tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + parent_id, + fn_id: name_hash, + node_id, + slf, + total: s.value[u_value_idx] as u64 + }); + parent_id = node_id; } } - tree.root.total = 0; - for c in tree.root.children.iter() { - tree.root.total += c.total; - } } fn read_uleb128(bytes: &[u8]) -> (usize, usize) { @@ -152,48 +149,62 @@ fn read_uint64(bytes: &[u8]) -> (u64) { res } -static mut INTS: [i64; 4000000] = [0; 4000000]; -unsafe fn bfs(t: &mut Tree, res: &mut Vec<&[i64]>) { - let mut valid_refs = true; - // suppress irrelevant warnings - let mut prepend: i64 = 0; - let mut k = 4; - INTS[0] = 0; - INTS[1] = t.root.total; - INTS[2] = t.root._self; - INTS[3] = t.root.name_idx as i64; - res.push(&INTS[0..4]); - let mut refs: Vec<*mut TreeNode> = vec![&mut t.root]; - let mut _refs: Vec<*mut TreeNode> = vec![]; - while valid_refs { - valid_refs = false; - prepend = 0; - let _k = k; - for i in 0..refs.len() { - let _ref = refs[i]; - prepend += (*_ref).prepend; - for j in 0..(*_ref).children.len() { - valid_refs = true; - (*_ref).children[j].prepend += prepend; - INTS[k] = (*_ref).children[j].prepend; - INTS[k + 1] = (*_ref).children[j].total; - INTS[k + 2] = (*_ref).children[j]._self; - INTS[k + 3] = (*_ref).children[j].name_idx as i64; - prepend = 0; - _refs.push(&mut (*_ref).children[j]); +unsafe fn bfs(t: &Tree, res: &mut Vec) { - k += 4; + + let mut total: u64 = 0; + for i in t.nodes.get(&(0u64)).unwrap().iter() { + total += i.total; + } + let mut lvl = Level::default(); + lvl.values.extend([0, total, 0, 0]); + res.push(lvl); + + let totalNode: TreeNodeV2 = TreeNodeV2 { + slf: 0, + total: total, + node_id: 0, + fn_id: 0, + parent_id: 0 + }; + let mut prepend_map: HashMap = HashMap::new(); + + let mut refs: Vec<&TreeNodeV2> = vec![&totalNode]; + let mut refLen: usize = 1; + while refLen > 0 { + let mut prepend: u64 = 0; + let _refs = refs.clone(); + refs.clear(); + lvl = Level::default(); + for parent in _refs.iter() { + prepend += prepend_map.get(&parent.node_id).unwrap_or(&0); + let opt = t.nodes.get(&parent.node_id); + + if opt.is_none() { + prepend += parent.total; + continue; } - if (*_ref).children.len() == 0 { - prepend += (*_ref).total; - } else { - prepend += (*_ref)._self + let mut totalSum: u64 = 0; + for n in opt.unwrap().iter() { + let current_prepend = (prepend_map.get(&n.node_id).unwrap_or(&0u64) + prepend); + prepend = 0; + prepend_map.insert(n.node_id, current_prepend); + refs.push(n); + totalSum += n.total; + lvl.values.extend( + [ + current_prepend as i64, + n.total as i64, + n.slf as i64, + t.names[&n.fn_id] as i64 + ] + ); } + prepend += parent.slf; } - res.push(&INTS[_k..k]); - std::mem::swap(&mut refs, &mut _refs); - _refs.clear(); + res.push(lvl.clone()); + refLen = refs.len(); } } @@ -201,104 +212,54 @@ lazy_static! { static ref CTX: Mutex> = Mutex::new(HashMap::new()); } -#[wasm_bindgen] -pub unsafe fn merge_tree(id: u32, bytes: &[u8], sample_type: String) { +fn upsert_tree(id: u32) { let mut ctx = CTX.lock().unwrap(); if !ctx.contains_key(&id) { ctx.insert( id, Tree { - names: Vec::new(), + names: vec!["total".to_string()], names_map: HashMap::new(), - root: TreeNode { - name_idx: 0, - _self: 0, - children: vec![], - prepend: 0, - total: 0, - }, - sample_type, + nodes: HashMap::new(), + sample_type: "".to_string(), max_self: 0, }, ); } +} +#[wasm_bindgen] +pub unsafe fn merge_prof(id: u32, bytes: &[u8], sample_type: String) { + upsert_tree(id); + let mut ctx = CTX.lock().unwrap(); let mut tree = ctx.get_mut(&id).unwrap(); - tree.names.push("total".to_string()); - tree.names_map.insert("total".to_string(), 0); + tree.sample_type = sample_type; let prof = Profile::decode(bytes).unwrap(); merge(&mut tree, &prof); } -#[wasm_bindgen] -pub unsafe fn export_tree(id: u32, sample_type: String) -> Vec { +pub unsafe fn merge_tree(id: u32, bytes: &[u8]) { + upsert_tree(id); let mut ctx = CTX.lock().unwrap(); - let mut res = SelectMergeStacktracesResponse::default(); - let mut tree = &mut Tree { - names: Vec::new(), - names_map: HashMap::new(), - root: TreeNode { - name_idx: 0, - _self: 0, - children: vec![], - prepend: 0, - total: 0, - }, - sample_type, - max_self: 0, - }; - tree.names.push("total".to_string()); - tree.names_map.insert("total".to_string(), 0); - if ctx.contains_key(&id) { - tree = (*ctx).get_mut(&id).unwrap(); - } - let mut fg = FlameGraph::default(); - fg.names = tree.names.clone(); - let mut levels: Vec<&[i64]> = Vec::new(); - bfs(tree, &mut levels); - for l in levels { - let mut level = Level::default(); - for v in l.iter() { - level.values.push(*v); - } - fg.levels.push(level); - } - fg.total = tree.root.total; - fg.max_self = tree.max_self; - res.flamegraph = Some(fg); - res.encode_to_vec() -} - -struct TreeNodeV2 { - parent_id: u64, - fn_id: u64, - node_id: u64, - slf: u64, - total: u64 -} - -#[wasm_bindgen] -pub fn tree2Bin(bytes: &[u8]) -> Vec { - let mut funcs: HashMap = HashMap::new(); - let mut funcsArr: Vec = vec!["total".to_string()]; + let mut tree = ctx.get_mut(&id).unwrap(); let mut size = 0; let mut offs = 0; - let mut max_self: u64 = 0; (size, offs) = read_uleb128(bytes); - for i in 0..size { + for _i in 0..size { let id = read_uint64(&bytes[offs..]); offs += 8; let mut _offs: usize = 0; let mut _size: usize = 0; (_size, _offs) = read_uleb128(&bytes[offs..]); offs += _offs; - funcsArr.push(String::from_utf8_lossy(&bytes[offs..offs + _size]).to_string()); - funcs.insert(id, funcsArr.len() - 1); + if tree.names_map.contains_key(&id) { + tree.names.push(String::from_utf8_lossy(&bytes[offs..offs + _size]).to_string()); + tree.names_map.insert(id, tree.names.len() - 1); + } offs += _size; } - let mut trie: HashMap> = HashMap::new(); let mut _offs: usize = 0; (size, _offs) = read_uleb128(&bytes[offs..]); offs += _offs; @@ -312,12 +273,12 @@ pub fn tree2Bin(bytes: &[u8]) -> Vec { let slf = read_uint64(&bytes[offs..]); offs += 8; let total = read_uint64(&bytes[offs..]); - if max_self < slf { - max_self = slf; + if tree.max_self < slf as i64 { + tree.max_self = slf as i64; } offs += 8; - if trie.contains_key(&parent_id) { - trie.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + if tree.contains_key(&parent_id) { + tree.get_mut(&parent_id).unwrap().push(TreeNodeV2 { fn_id, parent_id, node_id, @@ -325,8 +286,8 @@ pub fn tree2Bin(bytes: &[u8]) -> Vec { total }) } else { - trie.insert(parent_id, Vec::new()); - trie.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + tree.insert(parent_id, Vec::new()); + tree.get_mut(&parent_id).unwrap().push(TreeNodeV2 { fn_id, parent_id, node_id, @@ -335,69 +296,24 @@ pub fn tree2Bin(bytes: &[u8]) -> Vec { }); } } +} - let mut total: u64 = 0; - for i in trie.get(&(0u64)).unwrap().iter() { - total += i.total; - } - +#[wasm_bindgen] +pub unsafe fn export_tree(id: u32, sample_type: String) -> Vec { + let mut ctx = CTX.lock().unwrap(); let mut res = SelectMergeStacktracesResponse::default(); + if !ctx.contains_key(&id) { + return res.encode_to_vec(); + } + let tree = ctx.get(&id).unwrap(); let mut fg = FlameGraph::default(); - fg.names = funcsArr.clone(); - let mut lvl = Level::default(); - lvl.values.extend([0, total as i64, 0, 0]); - fg.levels.push(lvl); - - let totalNode: TreeNodeV2 = TreeNodeV2 { - slf: 0, - total: total, - node_id: 0, - fn_id: 0, - parent_id: 0 - }; - - let mut prepend_map: HashMap = HashMap::new(); - - let mut refs: Vec<&TreeNodeV2> = vec![&totalNode]; - let mut refLen: usize = 1; - while refLen > 0 { - let mut prepend: u64 = 0; - let _refs = refs.clone(); - refs.clear(); - lvl = Level::default(); - for parent in _refs.iter() { - prepend += prepend_map.get(&parent.node_id).unwrap_or(&0); - let opt = trie.get(&parent.node_id); - - if opt.is_none() { - prepend += parent.total; - continue; - } - let mut totalSum: u64 = 0; - for n in opt.unwrap().iter() { - let current_prepend = (prepend_map.get(&n.node_id).unwrap_or(&0u64) + prepend); - prepend = 0; - prepend_map.insert(n.node_id, current_prepend); - refs.push(n); - totalSum += n.total; - lvl.values.extend( - [ - current_prepend as i64, - n.total as i64, - n.slf as i64, - funcs[&n.fn_id] as i64 - ] - ); - - } - prepend = parent.slf; - - } - fg.levels.push(lvl.clone()); - refLen = refs.len(); + fg.names = tree.names.clone(); + fg.max_self = tree.max_self; + fg.total = 0; + for n in tree.get(&(0u64)).unwrap().iter() { + fg.total += n.total as i64; } - fg.total = totalNode.total as i64; - fg.max_self = max_self as i64; + bfs(tree, &mut fg.levels); res.flamegraph = Some(fg); res.encode_to_vec() } @@ -414,3 +330,13 @@ pub unsafe fn drop_tree(id: u32) { pub fn init_panic_hook() { console_error_panic_hook::set_once(); } + +#[cfg(test)] +mod tests { + use cityhash::cityhash_1::city_hash_64; + + #[test] + fn it_works() { + print!("{}", city_hash_64(b"123")) + } +} From c27a594567602b1f7c54f21d8e363d3e579a0939 Mon Sep 17 00:00:00 2001 From: akvlad Date: Tue, 13 Feb 2024 23:53:06 +0200 Subject: [PATCH 05/12] back-compatibility impl --- pyroscope/pprof-bin/Cargo.toml | 7 +- pyroscope/pprof-bin/pkg/pprof_bin.d.ts | 11 +- pyroscope/pprof-bin/pkg/pprof_bin.js | 46 ++--- pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 83701 -> 80195 bytes .../pprof-bin/pkg/pprof_bin_bg.wasm.d.ts | 6 +- pyroscope/pprof-bin/src/ch64.rs | 181 ++++++++++++++++++ pyroscope/pprof-bin/src/lib.rs | 88 ++++----- pyroscope/pyroscope.js | 14 +- 8 files changed, 254 insertions(+), 99 deletions(-) create mode 100644 pyroscope/pprof-bin/src/ch64.rs diff --git a/pyroscope/pprof-bin/Cargo.toml b/pyroscope/pprof-bin/Cargo.toml index 25db2941..daf87289 100644 --- a/pyroscope/pprof-bin/Cargo.toml +++ b/pyroscope/pprof-bin/Cargo.toml @@ -5,6 +5,7 @@ authors = ["akvlad90@gmail.com"] edition = "2018" build = "build.rs" + [lib] crate-type = ["cdylib", "rlib"] @@ -17,7 +18,6 @@ bytes = "1.5.0" prost = "0.12.3" json = "0.12.4" lazy_static = "1.4.0" -cityhash = "0.1.0" # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires @@ -31,6 +31,11 @@ wasm-bindgen-test = "0.3.34" [profile.release] # Tell `rustc` to optimize for small code size. opt-level = "s" +overflow-checks = false + +[profile.dev] +overflow-checks = false + [build-dependencies] prost-build = { version = "0.12.3" } diff --git a/pyroscope/pprof-bin/pkg/pprof_bin.d.ts b/pyroscope/pprof-bin/pkg/pprof_bin.d.ts index fb8be1fa..87b92058 100644 --- a/pyroscope/pprof-bin/pkg/pprof_bin.d.ts +++ b/pyroscope/pprof-bin/pkg/pprof_bin.d.ts @@ -5,18 +5,17 @@ * @param {Uint8Array} bytes * @param {string} sample_type */ -export function merge_tree(id: number, bytes: Uint8Array, sample_type: string): void; +export function merge_prof(id: number, bytes: Uint8Array, sample_type: string): void; /** * @param {number} id -* @param {string} sample_type -* @returns {Uint8Array} +* @param {Uint8Array} bytes */ -export function export_tree(id: number, sample_type: string): Uint8Array; +export function merge_tree(id: number, bytes: Uint8Array): void; /** -* @param {Uint8Array} bytes +* @param {number} id * @returns {Uint8Array} */ -export function tree2Bin(bytes: Uint8Array): Uint8Array; +export function export_tree(id: number): Uint8Array; /** * @param {number} id */ diff --git a/pyroscope/pprof-bin/pkg/pprof_bin.js b/pyroscope/pprof-bin/pkg/pprof_bin.js index bb57be49..6d0e9559 100644 --- a/pyroscope/pprof-bin/pkg/pprof_bin.js +++ b/pyroscope/pprof-bin/pkg/pprof_bin.js @@ -88,6 +88,7 @@ function passStringToWasm0(arg, malloc, realloc) { const ret = encodeString(arg, view); offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; } WASM_VECTOR_LEN = offset; @@ -98,12 +99,22 @@ function passStringToWasm0(arg, malloc, realloc) { * @param {Uint8Array} bytes * @param {string} sample_type */ -module.exports.merge_tree = function(id, bytes, sample_type) { +module.exports.merge_prof = function(id, bytes, sample_type) { const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc); const len0 = WASM_VECTOR_LEN; const ptr1 = passStringToWasm0(sample_type, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); const len1 = WASM_VECTOR_LEN; - wasm.merge_tree(id, ptr0, len0, ptr1, len1); + wasm.merge_prof(id, ptr0, len0, ptr1, len1); +}; + +/** +* @param {number} id +* @param {Uint8Array} bytes +*/ +module.exports.merge_tree = function(id, bytes) { + const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + wasm.merge_tree(id, ptr0, len0); }; let cachedInt32Memory0 = null; @@ -121,40 +132,17 @@ function getArrayU8FromWasm0(ptr, len) { } /** * @param {number} id -* @param {string} sample_type -* @returns {Uint8Array} -*/ -module.exports.export_tree = function(id, sample_type) { - try { - const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - const ptr0 = passStringToWasm0(sample_type, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - wasm.export_tree(retptr, id, ptr0, len0); - var r0 = getInt32Memory0()[retptr / 4 + 0]; - var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v2 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1, 1); - return v2; - } finally { - wasm.__wbindgen_add_to_stack_pointer(16); - } -}; - -/** -* @param {Uint8Array} bytes * @returns {Uint8Array} */ -module.exports.tree2Bin = function(bytes) { +module.exports.export_tree = function(id) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); - const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - wasm.tree2Bin(retptr, ptr0, len0); + wasm.export_tree(retptr, id); var r0 = getInt32Memory0()[retptr / 4 + 0]; var r1 = getInt32Memory0()[retptr / 4 + 1]; - var v2 = getArrayU8FromWasm0(r0, r1).slice(); + var v1 = getArrayU8FromWasm0(r0, r1).slice(); wasm.__wbindgen_free(r0, r1 * 1, 1); - return v2; + return v1; } finally { wasm.__wbindgen_add_to_stack_pointer(16); } diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index a12eeb4ef6e17749f2e9fdee88419d6b3d99c5ea..a399682f0e08aec3e84fba8d1ab28bd1a8f2f9dc 100644 GIT binary patch literal 80195 zcmeFa4U`_$dFNTTs@|`D-|l`THKIYXsVWIuieW9sSW*ZR_iYbg1u(3Wal9GN0c_)s zZW(ABLm1o4*V&*$SG~7x-H+!!-_LVzMOT0D11^dpcVOLB@xg=c;8n>% zyYM5r%JIK`>yAe$x7@4VfvZ~j!LNu1;l8TDHHuXEfW5B29jhD~KA@)b#(@LTRqgN~ zivKT{PG5QDhu-=AYv29eYp%WW`rTK*>zemnxBK1K?78yFGxgxTS6+L~hpxQ(o$tPS z$M$P>?tJ|_uikm}8{QN3PWjfx@YVQXU}zeu6)nVH@t59_8nKhXUFT_`L6f8>&4!)QI^BM?wxbjyld~3@7{CW^;hn> z<~>o8-0QyJTAkEI&ZT2X>f+dq_v7)2PA86|I3AmfhFqg)4gb4#JL0~*HjUb8>Kwo0 zB<{woG>+149LKG=7bo2$PC7|6;CGy+QPQGOmnP9zl*WTN=|@qLCJAdBCrRSceoDhp zH{vNp{Ks7yQNKk+YN^M_rLLF6gCuRa>)o5))Jj~mrrl%l{h>pPQNQzBZmj)*Yd&z@ zo}Y=Mu@79c=e^fldHtU2-V^OAf9&0J%{9@x`q$iW{dIfxUTMF6vS(1R`!Bf3_h0+| zy;oj;^|kMR*Ol+P?z;KtUbm*P>>s##_wMW76}^9LqioMLp>W}>M&Z@(e)pAoue&lV z?)BHb|JuFR?1?_UpKzDn`0o5J_c2O;-d*zxZvX5233r>j@jZ9D zU!&}^?ibz7?&I!=yZBWqKjGG1^*J~8d?IIbEXd&TOG)ViI^HbIV zGpV#rCG8)?p9r8u|JTx z4=rquqdu>7=a>RhQgi&-vpuG<%&`m^4KY-e3_5)Pb#EBxW#frfF*8V3s}x;0&cxrh z6x0ENwseA71=e8^35X@UbRTbtr}K`r8tccPh%RFMv7Z7a{ADznS-K&Ba@>_GsJh+4 zWs#;ylVO_N0n528-Jqq+(wyZ0RJ1}(Jz!};1fKF!J-Dh}Aky|U#C@7X@W8E5|b~1I<2M zgtZllS`S&f8iWmJpr=`9dps@34hzSq3<+3Kt-*BPaK{$=La_J!jPJgKK2)zf#&rr);dw@1@&Wo?^&r0IhJOkey$h%2U{ zdE3}@VX`7xMh4Kt7OQ27mk}pCMDQOikquXq7jX~Tf>OLE@VyvR>WFaw4p6DLP=L1J z+!D&o#Tl4nALG)(DWc1$BMyK0!hf^808U`!`_g$qf`kc+38>*%;*_iMf*1m?{xzWDE&;GD ze;=<2gCikn%m3z~bPhFS|3U$a+cy*CQP%aT!~qE3g?L#nd(N61yr_sbh@Yzz#H$Q4D^e(r zk{Qihm0_{!tuuGgIPa-#p@4+%!{u9sikZ7?gAi1OMxuTH2)F))v()_^G#Y6CHr*L9 zsw1oE@8QlEk*eOOA9wRdKXk31JfI)uL|{$Aje)UF&L(>c>On z6J6_SkL$-H&JuT6J6_SkLt%muM+UwdeHX>GFxLb+tpn>}Sg-y4KZ>>B;lu z6J6_Sx9Q0d{s@S=*46INk6X(py4Kb1(vREAC%V?vM6qy%$vG*w=z#MDl9#1uz97bf z5Zr0t@FNDZ!!#X=Qk6Sc$|7T2C5~RfVXDrVq{ME%37x zJ|Gl7N;UK%RQJS$9EOv3G9^$xgzIkjN`};$<5l5Up<2>f^f&-Uiiz1g45~GkwFDNK zoB|7XfCYW3b!xE4W?QE5t^kV>l*F}xy|i3(0pq%ZR^Noadc!oJf16`9QC1aYP~-|2 z+-Rtkb{KTNZcqu4zu&jsT*n0^qG3_mR(>{WL* z0uhIBs2%|}f{lu&VJxg}7>unmTA)^U*<4B%;%lF>!wxLFlI#XtJreiBWAw@W2S;GN-0cnGh^=m?qoc6 zpnDJ}(#%{jX-=dAk_q7-i@8R$>3qHmvrLPd%@-4MIVP0jJ8$Zne^M{ zvLWO2i@bgU>}}0{=gEKj>|cNV#8>Y>c(jOzTe8Wm$xiy@vJD$*(r0toz-L+7sCZ!Z z__yx;{jdJ)U;K+V@dDU7Ukv=rLNT7XOJL-@x+S+umUrplwa2p7(dO$}d(^BqkO zpT7O6g9nO4^GlCr$tuN5%SwTQqM{+N0K>QCiF$9Yb=mvUwMH5+fc;teQHFuRzp|^B z(m$&p;o!#8+5h9vm!JRbKl-z0K6wy!uAzv*jceLAEaQyX_)8yOqrn4mTY;OPbUqMf z@_*~4%(96A1+wGBe!%_Bul>JA{_?rMynENt*>i3I05{?RYJ-f$EwI|;#@W*-Y>lw# zz$%OLQb1!4FFy?j_0#jkP!lf~$R-oWvlusInJAab$ZSH$GO?62HR%9B1M38>b@@G< zE7oRf_|eP4b*urE&JieP)wPc@F^iJKzdNenr8%*`0gx=+FPzywJGcd~Z4eAIVf}PX-?du{rld4M3jI;Rxdo3=-xI zUlY59A?CQ_{I>agt*ueM&cj6DW?(OKUuP?pX2Wdl@NIBIyt5$p61I6jY6dU^2K$+L z6OFUZQGnmw50^wIvMzfh!eTUp;muf;lg@m=dhZf_)wI$-|TsM+}HZ&*ibXWfn2 zT82%{b)hr7=Dd;2odcFdZ(;Ofnr5RntCqtnXnrp1`!n_x>G|LuUC#3=h4h_S(HMn9 zzS6xI1S;%;Z{=?dkZJ7TMMhiRwWTt(ZDg%%qFj$`VxA=duF?t2`Xg!(v5djN4#O%` z5UdQdq7zxsDAQ7IKwDONb78(~e8CK+fQsIG5k3tbWLPPz=5V|(`1zY~h1_7lAawzk zL7nX^_~>FL04Uleh*`s^Sf|D79Gk6H-yP1@&A#xrfAiOW_3eNCr5BN9|MNQGXuP=+A$UH{c!PEOOQc;>?ELCYNGZZ-HkOhC#^kEHQnX?4-ZG zT%k^Q9Z4?5a5DT7mZn)hAgj0-3nCv>@NGSf3UTw90zIPDL7E7a({y;9fs>8CWBKN@Q+wn2$Jg|JkOLzLGGwAMHuB0%e%Blq{oCLiVD2NLV}8w(74^><5KLLYAFCyG5@#2 zqy5UHC`;gaxVelVG=eW3{BgJ|%hdQ0H-7|@Q#J7nKnOEz2V}GLS5szr@U&_}HH9-s zL2;^%P?MnnaIGcsY96;P;}N7NkIs!U>P^IvgCD`0c$RA9jB6ilX?VILT%M>|j0TJd zvDB8pGXyKROy!a0rVc@2+504G@N`W?5Hsp~H)#PUfXyTDTMq|oT$F;k2A%jI?~A^* zQfJm(Ep5g+U}U@cXgTWDnkvT=8a(BL{g#> za*efSehxs?s2mIMU?>-3bW$JD3DOvSM5r#}+P{FexqK(Ay@|z)GG}A6!niJs%R?UOMf8iH7f%=6<#L#V;t(_1su4u$pLYu|A;b1q_=3lbhjV!kzyYb; z(G(^wn1b6AuG`rMd9?TK@d(-Og3Qp=Qb|tnu=`>UjWMp;EM4PiQkqH0lo4|C!chYl zBk1n)FWmHeXMtP0&cUqH-2`%Rb+Q62p(_lvoJ|3ik*89Q-;Ksk2T&Q%JX1&z9Nl4( zjY=9u%M0dbst$qIvY}|y5W0V#4s2K(7a061qY`*S(iG^8n|Q&NUXGy=_#GHvj3x%| z!X#1@T!llt)WA#U8+b``BfJ!ofrp`m1tw#RR884x!n&#kfs~pwM6T7Lr2j-ao(Rci zH~`bl$gbQtatta!uEm%yXy4dJF`?9j0Sv-utIP?roD`^WE}sO2TGDZNw^j7$nDsXK zCKClzWc?6x9l@qoN;nlF;ksN*!gVDlT6++mJ*J$u%DN`wB>ln@)?F`}sFRW?QD@C| zNAjnI{vs*Y(OY}4Q-YMkCI(tLR*C4Dr{L1CltJf4Df*k}Ej>4y)SroY6KYn5R)ims zxs?(>F;`!fNKW-cOkq`!QC)Fw=uteX9cm#0dV%EH<=S0p)u=dTuR^!UdJR` zj_We@MmSQhi9~J1;9IjJ8D?va+qf7k=yb^CT?2Yo+9wi&fuD(y$YsOj<0j65|M_5a z;>VOQsK^)JMVU z@ei}p9G>_@m9}6}4h&QE3nNr?$@*ng(T?e3EE`J2teWp*SmHZ(EXg4UPe0Qu5_o86 zw?Y3i4n%eLJ#_d_Fx+`lC2fCyRr1YNoE}U{ zQ$CSn-bd$07-kt4rpvg{1%q5)`WL|ku}H6yc~vL~S-|OlxPD4(nDU6m)AD1NnEYCBPM#c1|X@<+j!30p*nq&~mK+3@dbG|3kO8n-z*;qkTWS)%e#6NbM zqUO`wQR6%YoZv^0Ij*}g?snQ;pSx|8U?l71>AB%6vS|2DHQzol`+_?RCF9R$U{b14 ztHDHiRQ`-9y(a7sRZ<;0dr8u9^Flu#y;(EY)3|&(p{Mm@&Cnhv<>S-rapO5UB=z;i z3C2J}sc|FaC#pA&?FL=KZsJ!TvjVBWC89*h|bTd`xuN-_6SSiQ#-*YRPK$ zJe9X4wvMaLyk%EXR(9^&ax^x6cVyHyep~jO24iFOz5eh6B90FBv=>nYgXrUZ*HUna z2oY$#6m`R|%uQ@*b<6);((T68kLIg3w z^+!+IBW3HYcjUrH8DN0Ot?I)Il9wQRk1X zPOxtT66!i7Bp+n1{k?hYbA*4Mx8oU8yP%PM(oE4l_WB3lVP;A8_ZA(obSw$bu7hU} zeg_R@vVS@_@KBY+;oI2lW~J#Nnm^sasl@Q4|IujO;%WQn`kO8K75AZ%>6iY&sz;uq zfGJB`@~Y+UuO8qIj27@%@D^i{TCI7b7h_S=AmdTHNCjCvkTJHcWfEgK$hZ{UJ@~&e zEto!fG=m52)estTEZrq*=LS%>AdF0X?jQf%l9RV+*gsYN!UVLTJD(vNfUJZDN*GZ~ zsdid5fWatrEAJ*Z_x;ge-aq<#uOYj}|MSmt-@D6N!Wlo|wneO&(l>C96P zWc=^_KV$Qrl_`hyP&DtKIlOn5>?)pq{C=u$@!!(rGqJzvi(G$`+-Q@?eZxEXAjC5d z$v>h#<+qar5w8WkWZwS`KPTbEBqlBR=RX?&e10TvJ?iGZrKRImisrhcE^blk4wjYD z8>Pc#rIKAFp)V^X%ZDiWdofEq`7z-4`OuKzeV^x7!;QN|sk*7@7{4H{@3 z%w(%;%Mq!(2i}>Od#$sYksm`wQh~{ji6H;~J9)#GF@FbO8{RHO!=dMle&K9IC+Xkc z!b#;{1J*wTG!gd&UN5#{Y{2gghd@<|@g}glBIrd@+$mV%Coz3H=DBD;mf6y?Dl%I_ z5hjZwgvtcM%h#{03p~*cbEVHBH=Z=i6@2Cns8Ow3m@;F5mE-zJA{T)aZ8IOuYX!^Q7dWr^ek|R}jIPS} zgTA4OAy%d0M<#XDRv09mD~Y-3{Rwl%{Zzp-Vr&|+5}(aT(I5>M+A>2F$1>@|dMs_t zfPsio1^$O?(F(&*EB)tNXc8iR?dTu_Z(jPX5^9PF4@#JMJOlAtvLgDaiDYw9phc6v zm%(YobCi_CyS4>}C8wfKE?wpFsk4ySgNlJlDmy((hOZ3RrHYIK*$zg; zRT`P>nz-)B6h#|pYzcCa4EU;1hBX(`1M87384TS?M-S<9qp{SlnQFq8Eu14L)Mo=~ z7m~Xl3DeZd*`y+-sH{da3(^_Zqcrm=!F?gRsj|Xp3ORY!Wy(RHta3NGUz$ILbhd`; zK~)pZ%-Xb!FIBK&vl=zlhr+OmB;lo~aYQQoj{}SZA671RHrva@q(P zqns>Lkh?Md?_++#F?OAW6x)Lg*DSVC24Zv1P2x4z6^WV3p=3>s?*Yp`sK#n21Cdn< zn@%i0lb0z3pq3V=47jCfaVr3-_XBeDA4}u*0bHuk7C}-F2*WDSI>FMSA2_j3VZ&^M z@(R-se!zCN5O3*B>dl&}=H3uR+7~ns$K0cR5b&P4*GCb*lf5Ty&XOZM#jQe|Kw>o_ zmx@5aU{}h{Hfp}ES(7BuK0KY6@Xm!3Hy9WvDCy8X+G7Cc8Bm7OmOw zTeOITn)Vm1qeW*wu7S?%np=*_X8~iI&2HI2{1s;<9){s9G(f5hyr9JcQYEN1%|lj> zJDXEXa4a{+34JRWv!kF$Ebc&o=BNP>s!;#Tj?1)Mhm62j6G|Hq(XANEFjBhHQ1O^C zx-4O^gyl8FL__55RY%o2N`o3Xy&#j0!eqzLRJ05rvH%HeG`n^feHv!iVg>}t;a~@V zdFA#iSBf!}i>1j_i^YuQY`qY?^?IQ%?a4(AK))B3%Iayg>Uvr&7D%_cMAaFl2OQIDqIGYQ$pT{q2VFD1s|^VIH}mS5HeEC z4Y5)@Wl9(zb6Aluo=15EGg3~qSW}y|!Ud5Txl05P7B1z8bZM&4^Pu)IuffU4LYX|J z4P58YjKGe)APX(Qu?`veN9Sm0OyD z8K~%eqf8eAA3w|^D(Im&s}eR)gr0!O6GWDcmT~|?pe9D0>HsVBmttHpXa~X|<4(*k z@1Q(cv_@GFL*c)1mjJm@gG*XNzFBK*rz~6J&RWCxa5?@JYX&k^7R3}0FSm|r#fnwo zE!QYOL$wL;CIQP6-fsm>&DIo_YOu--q9~JUOucGZi3QbA1V0gay%CFSF$-^rd! zLy+%AekT}8?RSztN`5CwTFVEbj^85Bl%BFj+J?EjV_Dcd?wqP)>x^A!mD{ZzhFm{n z!a;ND1^1KuPF?w(h%dvR<#+0?@H@5fJ84S_v%v2}HoDzaz9!;sOMOl1py_L}-wj`r z{ciZ0?6>)vGyoePz9v`+1U~!#Cl^m})pa)j|%{=aE9+^o`wJ%Hy8@=yH6lSF8`B>zPvKm%W^%3SH-Hh0atW=RK@7T07GRnl&3l*C`5miPfL_pF37}R9Y z_%%_=h;5rU*3@}y85!|01AxZNWQ~?vvsJr@c zF&a0VPjV#;mgL=#n1t%00h4ze8j&1RpX20c_7^APbq8DJ!5r+VAT2hQ__6Ty6d6d} zx#4tvy2M)-xfT*Qb$|z+R>n#3K#7_1eh$npDG4}+I!Tc>y%#;-*)8o7?VdzW+`*Rr z5fV7l%yK{B@>!b%PF*MD|E&@@r4Td|IEkr9A1f0$ZL_kO?sWnu@lPdi5@>|uo-3<< zTan7#?Uo6gR^1XfdA1W0;BtXv8Z1Zm%>+(1;wxbg=t(CcoTvoOZb;z7uOby{K+`7p zTV%77^Vm{G+Oh=Bm}Q^H2IwF-s6p9S37lA&eL;TY6IjI9=5xy#=W3KjwVSlUy&iF79tFdf4 zbk?y1&XBJ3A_<)6yfir&o%1#q*4VBQTtoM}(ox)=hI#*&C7G*ZJ8itjq z46m#4%IXC@SilqctVj$-PwU_$&|U-*I>*X{PI>`_m<>xdtP?uHnR%)p6$C7$3`5ui zoBaELj@+-BaL0%Ov!&1LMDB&Ra{Tg3SliEr0eQvMf?d|n*3ynjNkt!ZP?o9PCQgqp zLu74mD$$qZ>2g7_p4K)7zNB3nI0+>tOF##B3#kDaQ5wl7!uW>pb%JLbrj2<;Vym5v z0JF0MPjRNS7-Xj(SI*Swvu7MD&X|26Iy}lRK9Cb!5~Z*kLOzGng)KoHz34;vP>~!YST-L5iw${mcCK0IQwV^3uF+-v(Z~|dZPhM&$^orizBwO z^?<2ZZ#BSjWGYr`FIyw8yX+?=m9jHnH56e-pH>p>K=rdT$Rvr#DAszd(RvL?Can6Z6NCOTQW=*D#RfI7muJVp^Nq@McL`fy_TLpY$xo^);=Tj6Uz{zx(W0T z=Np(?#XwJ|i4Dh!5Z30IzDZ9iPt^3nX z3k#8aqos5UN$^KWBTNy^Gpqm0IIL$@o&!t6kP+YNwOpLCef8_o8c!#WI2kakglD-m zBSJw`6M9&qB#mvdw8YwW7T7RlN9-|_RGxf0>w_Gh?Hn!$tWRTvwcf_bM<`5TI9cbo z^_fPFv)c%#&>41p!i5o#Q7j&plD{$QZ0oyBqVp&?!q}9Mk!nNx7WMBp%cZD0No1uH zu|OJUNYtREq4XQjr+pmEA+u5&Z?qp9go}n#N)C18jjY<;t)Fakcd2#va8&h&i)4HJ zW*b2sg;W8zIrNPqFE~xg>1xt)0HkG3Yl43K#2t%(1CVec9biVdn1=ut15P!08l+vq z7$_gULN~$#?%!e<3lR%ZnMypohv}(W@Z6T!-I8p2$F|Fou|i|YSvihU+P!=n6DzCNE7^NUA}>a$TD3p=_n!~ z8yzSus{}Jb9(MgnVio1_Pf86F3a?UAJ0+eGp>gzJ(qeuc#oO;YbBL1#Z(4Lu;reSYrozly_Jj($9k;dUX|KGh#+Sf6RG}qwYWruRP`>T*am$@< z`=6)zYGh&_1asn5W*djGt44B)8azssbU&(jinj1>(MZ2Y@Md#fo)ep^wjbD00c3ZP zW-M{#4ESQTT84x&_^++0#U4N^vBUn89QIh7D3~7T;3E?Sod+7hL?Mh3OcWl=-vW3I zdDzus@-LSBn^-RYCIe!zPLhA6DU3%`vTr<_eCe`pe1+^o7hW#=f~Q}y57Ho~a3uTK zEQA7r&THw-xpD&_4=J!clYeQDe@J@(;

(mF1-+;Ne(h9Ku@V@#U*L zp-Qk1DVW_H`?^#BwaRRkIa)YrIPR1hj-$Slk}_Db$^<3h!f0vAW^zHNMP=`j4@_gM zG6c_VoNATZGJ^@SSPfho1cAiyP(7vLAQq(In0Q^O1Y@tko{U3MKN}A#+|vr1%G<>W zYZ{If0b*%5Fv_sP_Pf$>=+Kr*iEbGo79MJaO@VPACga&@g~@VsrWjA!3fr{oH4-yM zD~vjVas+J8G@+%%Z3V65O9?^1SOFVpB}TPqrA1FkxKOYzJE2sCx(cXyTet@dI}+L2 z@$7fL_9y@R_^p5X+s{S>&N3_d5C8WseCHF7Jn_XRRWwaeGW&0y{H5>wpHKhkgHNl7 z99)Y2@@ro|{LOp+)fc~`B5kX6kj#$c&BiGBgEaTu;Y6T#_M<4gMws9YAc(PnowB30 zs!PS+#Os4dl5Vr}<|Bn-ZUp+YaEk8{Atc@hOJnPIkyy~LMVL@Eq%6gX9}-rK!$ZIA3Ue)aB@9?Jc&hM{m|0H{VpJ>d;1{ zks*oqi^(wt?&%|@8E%jE|65u>5NvyVX|;fluz=~`Eg(zvq6_$3!a+?iSyPr~;+eoG z#S_pwk4a`o7w-1r zX(ymEV^Rp5v=hdxw3Dh`O+kSXF{*NKb=rxFm!zFgxg1XYnpEQIa2q!~o9a3NsywlD zdCmkIQ8=~9ved&lrO2%1ITMUd;brL=T%@yD&IBEr-g2sAhj1r^S&W9bd_Jb|SfSlj z`4>`ymgZlq(pCkfe*fqCu{$sj?`8kX*ye~uKo!~;EL)RRA=GQ9w^kuka}Fk!VF2F} zTA+?#Mv(z|)(3rWxBn_+*WMRAi352OL#9=5N#J7BD=k=-!#vYHb{YQ3?Xp^6!1ysG zwb34q{LFFx#zu?M<`LtPjjD+_xFY3vXE^Grb>(MA0;05IRJZ4(8-UZxM@getO~kI{ zrNtdhyF213sZ_yg8=zneX2&jw#;L@4!1xmVIKK1YN70TLde|JK(`{28GaW_;i6prK z0?bGgWEAK%%X`**u>`3M@aBuY!H1M&g9(k(V1Q4jgbyX(6+W`hUK(fs3gd!cdVt2A zK(c}SI$N7@4^V~qu}7J-n(#z9VSJJ=L~jG$onv`yWWZn?Se)hHDA8A z?XSdAR)AV^)ljiMfdFa03c7%(BhZA%8z(h1mTCM&Kts&{n(=y>T;2&&YDOW45DMGKYPgiv|;F|U14bZMW#;8F!gplb;S$FiPB*O7@eGHAV-3Hv0PR`4|*0$ z^7s%qB;gH#!mLCtCYX^G4(xsTVqhlASPDlpPD$?_+Zs>FWhEv-wT&WmiK{WFo*a>X z7n2Pd&**4-ucRsz@5?rDIz30-B8mA0xLF!b0Ov}W3`Kr0H)Ly%;t{b~U!Y)QYmo&p z>QL9^M;@E6?q-{B9orY#CFakGKwG2KgUsAwm~j37Ss0k5|^{2U^uCaCp3aR zWMl=C4ErC3YNb{J8@6L2>Pj>t;k=|0CBri{Ao0ZF$_XDysMZqF~D+YaySIdBj_8l@@01jS23iL{@=u|BdNy*o@H)O4XgyH z4H4{NBuh8TTT*0O$7iC9Xd7!6VvoU5`Q=2-%HriZEU(jcjpz8!I2*?tVNDvo*1W! zhX-kR0Si>w|H+qa0|Gk}Vc55j7!=%e5`jb)!-}A!2{Cc1{@Nm|Fr3r|>nFMQucr`J zf5&IJU*yklHtG+rjp&HA{ihBVz-zVV8$1_@0Fcm}IimkMcFOw1MTvKAh9$4nE^^p| z7nnw3#n!`V`#Of*PFh)dp1(OqX-3I-rdXL`S)PE->e6?0olfPnM-)mS*s zpY^e!Gf`<;T%;ieeGzr;ZoQ{J;XP@a_Fm9owK7G&OV7lM`XcD)=p63}mU9J-hE4gypJz~q_>=WE zcnE_F?9)^r7E@{QhKk{w1KyZkQtBW59Ist^gtny*E9{m<{cng5u>iezh9xjIF8p+)m5%Ywp}!@Kzq>Ej`?zs!gRwTllj@1| zIyVBPm2L_*Jr}=Fa4uzi?T6LDWCL)W%o#5oi zf0Yy-mvn@4^yGAwbK~xR2C@IL2wXV`_DctLjruCZsn8DCipeqT7vP@i#X4%qM z<3-rDxv@~Rwd(LoQ2`I7_Y#!zUADCYMom{W{O#)g4s{5K^@t&PdNb3ShL=efs6^nMsYAaMvW;}3MDNId=G$n9AF|z zptzSTZlqh*Mgic;p_^P4RX&Toi-ND{2jIdB1X!?5mJPC7JOf`Uk^-vWfpicxCA($# zV?yJu-UMkaM~fwq)TP(J)%5_A#rPDst7fJCNO7SbNdUFY-gYgf1}#POs3sn0h>KIqnS64R?+jFPjVr)5Nzpt3oKD{#X-+%sCEG|M%mH z&5;KVJpHRBYuHwM+aE_i$vgwM0Wnj~VKY4i6^WLt!XdnF)H`saqJlzU|73J6s*~I6 zAN~AdG*@otO9&AO)p@#G8Q|1gRzrFhSRBp1@a1p5_H9`wk4)w494`|8ZzD}F)}BEv z0%jP2Pcu^M9+OkHEJZ2dK!fEiB+Eu16kst%U1%peivbn+$0WkF$_4=cYRGEHW;rUL zi~j31@l=SV9Aba~5ZnQUE)WcccIb8Y4i-an298EYhnA;-$R9aXkOMv zS@dxIG@IU$Jir*T^*fULxXL$uQe(QSe1r14%IAx^$`s!bKMSwQ9hChH4sP=&NXLRW zIA4U2#U!>fA&WDZgU}wRQZ>ltGIwrFG>L*G)x57Ir+{63vJznrXa-2>&Tf7xcaBqr z_hpedT6y@POdHi>-C}a*bR8#m4xU0&9Daz5U6MN|raj7?)4@kM)XvD1dkHLg!E)y! z{}kj>oqiaJ?Np~9TKyHLAJQ{oOii6v^vcr@l`(|c(m4H)Jsg`UB=D2bo+Z!q!;}^J zcq*F5>NIP5S@zs|fIOb{k%x&Xs>7cO1k$b%v$SS-h_q+9^&C$xZ5poH5I{RBuRnh1l4DstDn-H;f0YSMX&0 zVGy{JonD88^mQHEJ!-;HMsM?7tCow?%6DVwb8XQLlbYAzaU^w$sjH|%AwuD)Xg9eh zBqf#i6d227b1cCY8we>|*0_xPE1N-1-&iaavj6 zUb|7m_$)n6)-EVxX@QnbAs{g+rN@zvB^NQM!;|W~Lqp#nuMFYVGMbn=fF)*R5H2{R z^IOmsP&-J^;>!ylNxqJUcH*JHo=;i$kW;s_bwZzsg`!8`2&H)iN(fhdx14bkiKHEO zRzso^U6Tq?3A9bL`Fv*iU(($Y^)49W5&v#rixqz zz)M9?FG?Cy1ajl@uE`hPLEA8yadT_{O+mTQQD@Ako>-TL+p7uj?c@4)u{mL>h81+R9T7 zVdFFNx%8sDXlOF<*lspWv{=b!M2k;f9xXmYm4v$kDLyS*ZXp|}Mn2pbM-6YY^{0#$ zuLpF-rk3Wzt@nFSmy8GbT+xKNEAC6*n{3C9niAlY#G;RrHCDmkU`FJrVYT$*s=YtV#hRK=mB$p zWrz4ZpR?h1AS>$0&`lrZ+j8iBQu_4z50hm$VvCAto@p^%W zR(g4>8Ik6K-qIgltyMh~^8>@0XoD%V_s1@gk-%Q1O5c{am1kfhLUmYfe$FiIpO`O7 zXd&(){WOQjOvs?Pkx4_mW1Ih`xFN@yqLuC10Gx#1(!8Yp;g{i0x-S=R6kj?dYT&PI zHRpf-^NTVWtudZ>UPKcU(x0lc9WQfV1|VkuqUA%*FEXTX+QQPG|4VS)p!vx0!RaGH z)I-(RHQ8WYeO;4d<#?j6YbN3AnhBa|__`+Yej_lbKC!7p(#k_311ICimhkyMxlKTV z@cBPX7n3;3<&$L-ix;D0u^ffDA#Yfa!w60-z&XCr3H0q7opJq*P8w@`V>38JF|VY4 z<1xchk*q_vG8bz=F@Dyci)1BDZ!_a6W0gWoF9h?@S;_$-8Rdr2PdJUe)Bobg;~3jH zbNE~|ex2Qr`d2gF(#gR_;^0i6Gp6QmigiF+7Q;?i7tIiDDNRmO@) z7Y-m{E-a)DJ{#l8!Dnqo5?g9W*qF#n+d&o9gma*72^Sy&K-Cb0so=XG3k^Gls8i2E z2bd`oWC^F9wG%CaKA}XH@*NcHvZYfc`Kgw<6x%!feL~c2#wS$9; z0oMnaeXAr>T(tl$o(VL{l!NJGFkWHHYao@~&6fc9HL~UPt6`^?wtVvqHnuFSQ#Vny zNjQZXr?BPG4_LU1(vgFic}jw^Qf~NqrZ6L{)hF|A68F>EDbG~MiLzZ<+Xf9Vxi+k| z%~>rI&otQyV$lfj1|`LpnllLFTV`6ba&l_%9#OyHl@-K&)c;%OTH0Zs38pSEw%2K? zZqDo@2oRF|&@FxJq&2%3K6YY}ACSfZ!Esr=dj$Ra6xI2v!Sd?8BlvDkQGI%4^|rpE zvTAiy4s;rPTBNsdju^wVBe0pm>=ZdHe71s=6*5?6Uvmo&w5Rec8hToX&U0Aa!+Z$3 zc8P*zwt%n$@i!-zD2lS3h)H^aqywINJ4S{jtG%M1`urlMq`abFI{d$)=in99shf#E z_Nhgo1_&<}rR_#kwkAH!+em;FZ>c-w!_lgIopICGN%hj#DK}8?by}JEI(eovC00$o zPRdJPCwJ!tUnedk`8xIT03_PRSfExsnvHR4-tdRotI2)o)nvyQ#*`Q*?+UeSC&A4? z@_0g*L5rCgXJ-eKPcj)ogWMjUElFk+Q-$@?f+%hfA<_CU){+>uHttqO0Jl90aJ zE`xX`V+XSgKx}Yj)isT%D@1Fid*b1h+8i?464_(PVMaNI(wYQ|EHbs)neM?@Fctdj zh>P?Oj0@#ias^*5H8qEe2z^8UBY2P!5@}py+6~28>c*fM{L}4A?-%XJz)i z%wS+U3Cg`w z^}0r84jzm1f4?Ieb*S@IiAHOv^oux+{jI+OQ#gZkcQZwi4cZNgC%jIBXWH_5nFAJx z{bxJSQt(Zxn8nu|nNZaS+MS8y8PVH`EIDzYXwPQHj$;zDmjH8Kn?0o)iv22(Yni9= zcB(A)&q-TkkERT7))my+VT&j|N*ogW895kZaxrglc!W5loz-U@f_jBeMKuU9Y1o5t zBN}JG3BLB-bc0t+G7`u^WOrAnk(LLwdsRr$DMref6vqc zds|L71bT3?z?GR^=`b;^$=vd}DZhih_=z0{z=ew9$swD-!GjW+G@$fAQJInx*Bq!T z4)hWjF<=k}A}*S{gyz^ODK5mKz7%Gh*_JPWwhALgSAu`Qf$*^!BbFlbVacsJdE7Qm zni*)!xaL737LI90efe{?Cc$i1PP7&|9TPdoE73NMpOV*x1xg-G!@}zFrtkm3U4rB{5je*D>9;aVdqfc&zO8N z{|Gt=`B0OJ{_`EVU_M#JEZ)lA)|L{cwImhpwMbZjy-J-xAXlx?Fq}tbfUO>*P#ZYX zxHM=sqd88fu7Uz+1eN&>a>wQ!4+tRr#G2sHs?RKP2Qv?;oN(o~9wPabBFZ<%#T z>P?+1CznK(E0=_<%S2h1iIfC{NumrnRjM)&#i5I2w#ttiwI$;||hO}J;1iB`WxxtOVvltO^ij+Zo0WwqZU!Yt` zZnu~YU9%L+vtwDD99f45wAkPB#{f>IN1^i|3?xbak6i>FImT+M?1Wb2wZmBS{Ujw( z2?KO+zfp#FI7-=8T1PM$1PX@uvUm~0ghLH)vJ?JANmd_!$g=u%U^YTOIZ~tX+E!M{Fv`= z#U#F#UkXS8Hsqq?kFgVhc?E2*j6fu#_KAfR2^-Fh&}Tq(7GRr<4Q)F|)dy8UZn&&A zoTIcJ=NKG#Q^U$r06fZNaCI&kM{bM^E&^rBl#rbmn#C$88xGsj6eFKx+d9Qv?PTvs zZ|cpqe;TW>dmJZ+K3_E2M;&PwZ|`^>1tYYD-Gss#{vlKd;VW)A5j!bc5W$t7J#tEX_vKaZE{|~yfhi?rrde|2)7_X6yDz)F<(Rp?Xyo7hYqe~jz zQJ?`WT3|3^GSf?avBr_1Y3WYd#~skQ-g|Fs1YE86-X~%2y-cLA_ntci^vMj7>rpT* z_uiX@CxQsO`0JLcZS~gDrGmOP;>n4n+pw)(jW26W>lL=&1?QTqVGJ)&sirg%go6Tf z@2!E-aLd}s0n`bfcThr8_`HMe!si_%hv`eZ8p6nhmgemGH3x&p!a~|&HiVCmrYUyp zUSdTY*2GE+Ij-14L!e|PfVAXd*LJK$dB>_cc1jx_Gl_;Y3BoC|y~-03RG*MB@%HG~>W zwH4@0l#N}!0Si7)eU!U+2GT{!$;=^;C`#os5P-rv!Y4SuASNh#J~%DU#fsGzBcj8Q%o{oDHEZeP-VV=2&cqi@TkH#Z{(qOxNqwm? zj%H-=!MI^;g4~iZ>7mW+-G(7jk))T19pw@8knFa3*zurbMDTi*(JdpL$Dz=ILRQoE z3WUPVigTl$kOV2!r~mV{QHag(B1YlHl}6zdvzc0I6cPqrW)x1zDAYEcVMHGyWELIXd=QX;6nHM!Jjg*FfigEN0=B2Ox7Cy4@N5> z36)0C87P2d7w(kN87V@mr9B$ppm2KRAiI#`9vnX?v6=iuQn76FWU{wRU5w{~+0gCZ zVB0Xs!L+DW z{*!v{8qcL$^R6nn{_e0|xD*T=fpk%Hv>MU|tFPmnGw1VA#tM-Y>+ic;D@5Q$$1jMoxK#vLwAa|HfXhvZh2oeR zxoMkBfZ+sf6JK3ois}2qWCAIK01kY0vqdsA7tA?c7vmxS!$14kFoW2#AsKpr5*h3v zfI}5>^CtB+0+Ur7Zia0K2is49XU3L54TV2hVcVe3w|)4~WNM%Cl4}oU!r)}kSj-hO zS2GA~+%h9rCD}kvAAw;Jj{5iW@y3vP$t2c6LF)uOFmSj#TPLmi6}oiuSMn)r%pjFA zF*qirREEirDG7R?1ktp)i_ov=r|n6399};B@c{kiUuD8SZkAEopR{8L^Gsz=xZ*7O zR_@?%6Ju->e;WQ!F%&%v{bSMG@J6mr;FuG0pm$*hI}vae?TCLe^q8M1m5m(IK11ne zuMph(*(-%MeSe3Wo8`=C9{Ah1#rdyWav)~A;r6+xE`5sIvhK;c)cjG0IRD|8%lh?? z>l^oPr$NSbm!8u;hj{rdq*(YZe0=##e%x)HF>ZT&1tkP3Ck4K!%GT7G8w^_zgL#we zGbo^{Qrbl5LIfslOyTXCCxt6~aVh&6+`DM>#g=Bn@3DVGQ{T(TelR%_Yq*e_t)_81Kv~o@q zmoL?)?Wz|}$C2xq$DGV!ZH|ulEuSZ>x7>=3V}5hh)P^nIgPBz0X{{KKwTv)O{q`w3 zCZ?vxol|w((NlPHfJ!kMhK~8o_vd*SKi091`P~#gFO_G79rL?s#WBA*$NaKmmff$p zx6e!6bqqdOPH`N0p~bF@3-+k4T=x+M zRCfRmvqO5s!~_~d+G=;Yy|Mmad;PA&UP zNG05}9a|3O7zmk@O%%+dDaqz&cmW|ZC)ZHMI&qoK3(3@O0W*YZq}d^KhX2qCbDF1A zny$X#9SKA%YX(H9ZdHs5x?Tim0;JOTCHjNNVun&B_zcFaV)N$M7As^Fr7EGjpz-T2 zX#Cn;M~519WvghaVb9Km;}awl(%68sVhpNBg)w{rN|*ldtwNhgamG9?Sx5(PVRD`y z{Y2IgxZb)HTpi;^;+w>S#rAYpF|s)09#+a%=If$vScNH?ol<-Ka2ex${Ay!7m3`df zG2dPR>>QL}p-wHkwkOL%=4`y3MZUs9&aseBhr^vddJ-&T2jEX%Vj(-TXVrl$WNVhA zQObt3L^U##?^@&Xbin0QxQq{LiG^$}g3FRzglQ+1A~9$HvcmW{lM7@O?lGp)NKO^n z1v4YwnPHa3gwP8IQQm2VcPvk8j2?}ZiA+lSoaNyXf{9ypP^oP0H zi-j~b`BMACa3#nPl5h$BFz#e3)iP$OKWvqjDu0-@bg8ve`oq*{@Q0bP3*CSNO^Fr! zVQWgs1uuc>Io>*3tDqL_OZId&UH{lJmu;wi*a^EklFS4xbXp4NfDZx9kv6AgiQx!# zis1-sOM@aVv$o8i2==P-C#KmZu{N6~O2O6gC)Vn#B@|1Q%q)Fk1Bhj22vQw!EwN6j zzXZ434=qcdV6~xs3t8}tA!j_r{vmyW#nbjFTg2S4@M|Sk8I#;ZH_^)tp~a9s0U@#2 z+H`oD5GdtBMM}-OGZI~6+R4ZfU`z%Q=e-aFS+m3u0Fb(3W2U!gyiy}LNiGwxP1p$h zC5SBu=F;ZBp%VH|)^icB?1t>7vxRa9avT`Ena@*3+l zP>C8})|%Q1R6;g2ic~3nz@ZKRHkHb6Hb)Jv9Wr*!H5Q@}=qU2F$v=S05WgO@0UbE$ zEzp5{A<#juNe7hdEtFlz3C+-fMy5O>#`@FfeCzjLBTpM1Nk_)PKBS-<~R!+nqI2#e@hBKQ5PMYt34+;j6ncxCJ8zP%ESjDC@y7^sd}X|1kWT4I%??eaF#m4l?wsH3o(Zk;fm3!NhnR&9$G(1 zgZ>`lb>t|3MuaPtjJ60D&5L14X8>nS8Cj+?V6T<7Xj6ZO`7Y7ltwq_QK}Hb8dod#v zE{p!4U5FE7(jS8Hi56kvJjA|$toCt5sKL1X#+ZY-9W6299Sz&Vbsc=NqV@l+s;=z`R5vTu24e>{3MHC@`KqeR1_ZRKPI^^D z434qu>jEoUe@xX;I&{8*sv~~O>adfQ)t{)U+ljCpiSB54zFH?%wX*t?syak6=mGRKcu~7#xUJNel?xB!;EIaO!JQV#Jad;_Up-o^9++lNe)u=WaGyjQL;u z>fLKibD9v7F&nd%7`WUeF%2}gJ*uf)miFKDVl=rRpmh*Mlj5x^NQ4P9u)6rjHt=|bPBbfITUU1(>;{~1XOUM~I*a>Don zN;e%oPnq8b3Lr*0>7R!G_gG^2jL`tlg5l&pfe7WY%;6)k8!ShO?dpzG4S=MCE>0jc zReY=B!sbF#DdC*WL0;e(LFF=eVV56JUQ8h`rdE>|Q!lf;0PSB)Uf?EMDKDTEqy!;e z4n{XAVFE%vK}(J>wv3)11O!POVVO8Dan656ET=mX5XLo4Q7Wr*D(}kb$Mx1&#Wl55 zRqO06T3P+KRJ}uWp)Ma0Bz=J03-TeXrVj)kLiMEdAxOwB^&yz_u9_E@mOfzn8)$f$K7jjf6@6gsi?8nz z9|ATX>$+C!8arjY#F&Or@Ew@EI=uqBW2EpFPG^Q#{8t3;)PGeM`GI8c3HEVzdJz34 zZRH^`iDmwV@|_3l)$qefZyz6oB zt}pXy+ORD=Us|4(cik*c1?nsBx^dg(f%@S1lkFKCe`4HpDBMQdHn@mN%<^I#&?Z*W zS+#gU-Ei1(mF|PgU0MA>t#wc8h71Z`k~>FgitR8x#bW>WqHau-pu*#61|n*sBbcdk zknHeLti5u%5zfP(wn7C{C>7(}f@r1wT=j}QuZ=NF??Tv4%iQ9+F_>HORt0m*5dm(* zR?eZVu=@D8f~@5|nPFUlt%c`?TeGz!$bzk<5tOzTLvy9Ag?oiB%>{2>Q`UZ4vR0Zh zA9kJegoMp@lB_NL?2@&(`&Y=?q>S@gFy=*UEfd+xc`MTwZ!P_^6$d@FtrZ7bs|6V? zwY6F@2+Th#Tg#eNcc?@P;jj1|(V`cRx^cFdV(%n_vWT#a}1zlPFq^iqWlCnj0Gp?+< zwqUIoOl>X6Pet|8xMDEqS}Uvnd$o=rM>dRD0J97%KnL_L&2VgK)GW<;95!ddyvj@b z0X({Pu-(h%(bZQmN`7Bj94)4v%53D1(LdadTzoM-WA~h`1pTW}TZp;h+A;dqOVum( zyrzE}a#B-!Qd4^(=gK({Sw-z;UEtl3XJngsyUeqqP1s3A?MX@P$%xt+NK#Tei=eYv zY^9sj{#O;XW7ALiBc#m;&7oeS(iaOnqe1T+ZBg3BTR7>)q>e+|9KKU}T!P!qH0U^J zXM792M3=)A}Y~J5XzPY}pWI`2I-^Z?tO}L<~nsC9`)cMqs z9C>06ag#9N^M}5pb5|H`h7XgIX~2*<4#Oq8E!XksQ8J@9)D&q^=SGZbv6u*l(O_@P zbE+=ri!c51@i+;UNcymRNQ-#YA6;bv0t7YLG^!IRf_aqXh20GE-1<2XdTahgXI%a* zCj>|&w=9~}uJL#_qLC=i@gC`R*`pjU(W=E}b|iL6*O&NgQro@{%_Pr>uuU}pIzEXb zP#(>$AIDuhh{a!|=Z3F3UBqXXr03dKoy^%WvE-{x6XB~)C_^mBo6B$D>dtgA9Cf3< z%Kq%zQ7(!iY10!rpw|*IE>Qz~_sN{Bar3)Rp(Xq76C72V0b5IA4hS`Xm`iFjML{a3 z3L9gATsU2%dV1-2E3C*#m!Rv$-Ye0D97z#1E}T_}s45x4p(-en*t4Hj!d@(&g@z z!HsH|6UPU`5hVUWk;H42Sc5lSBrMtpcRJSF)W=fo$}}&BzXyUd!yS1ZZ__3K9hC>V zaxpH9Q+@ajE0h*SsfMVXQ?Mnpbme;p!42uv5SlU#)EqfzWHKUd)LYG(>tycXvRDFW#cmnu_Wu(&~CS`ti zxtOy>pGh=-43vrFVNEP&N$Sojqy61#v}UkQ%JWx_Hd(FuL#nQL0Z6RYNq3~a4XCv(JCfT-Ce|&%`ROhE!7H~*$YRf0^I0rnbFU~)Gro0{QNS@->-y6Cme6br7yR8FM zfq#x&&OrFydFG@F@IdFSp1OP1x$TdIwt6;&V~Nh}bfnF47$0ZGAOXg>E{68`q?~^! z-0BMsXo>1oJs}ymMU=rcBrn3YPrlgBft*75Cj>06kLik==s{f%9Tp8dz^z#7LtMdJ z^x)m#>*L`UmXUrvs$XsYXu|y>_x_$l>-j(;dzQ7bU-u;%j!vbB3~=#1e68$`BpYst z-%gyh4TdFvCRV{aiWX-@$*m0xWSB6A#Pp>s)n&r+A|>|FHg%B}Z(C=Tu|eZ2A}dxoFG6Bpv5NvQr{yUM`G@n(w8-f_`C$gBGgF!E=IS7Ybb&BqW1Brl z5qn&O^YVOgsv*-efo%xFs+Ypqs6Q|>$zT9H3#*8UbV0Xj}1kHAj7g16Zu!rID&`nwyN7`xLz`U3w#EW;&ekTpQ4wx zN>6~sI}IH}(mp5H`};n!82Q)G%Fa3egzoP!1Jv#1lX`hc^`}++(Xu+o z+4pxs7TS@JCH%Oz{DDs;@(&&h*9Zxzl8`OJ}nu?3@3>Kq|%wn>_(Z`hw503I( z7~8_o`7Ssr_V_a6sM&687wN2yqtZVh+!{wYx|KY~(NPeFp%V=Z#nLLt6CNAL(^ROE zJnN}fXz*_?byo*c6Z{+Q-GBF?-JrQDO`n?NBQ#SS|jz7{bY zO5s`3$YTaXf{60=dBhrBe|hJ4xiD!+=c%axc``TkiS1VjrmTxMjwz)ZgvnBMpaAV0naU#|M-;WCQ1zD~NCE)vI z1ZOL)&piIqTsCRvfjR!=|KBW~ihsOk>#25Y#TM?=jd7m!VD`OL@zbgdxA2dYH?Vdxv`82?Atf%N9ZUa!E4quWTjE1OzX|eQ zS{^wq)G?lLYj_rzjXm2E-x130GzJvv-%b6WQd@W1Gc-F_R=%$+xIYy52N9T+en zLtBqjZGmwaM=|I~6QFLVrg!wwqT#QzFEcw!hnJwJo)u04L8VHh3ciBHd8PVW2Sszp z#>YvYEsuMVU&=_R{3R81gA>ZB z4gZuC4OlE4!WAAqgS(srdDi8*kLd-7iJD4`l2164;h3RJrvVNrTfAHKIF;TuWHQ@W zk{2hbY2=YiiLhgneW0V;CowQeL5Ict4&Hv=+Ic&7?Bl$EE+T}}_V_BhlY#MOyVFo+ zq}oR^w z;e>%@8kjT>rEp5(Mjn&KKlTaGmko{5a+V=MIs*>q%Ou!_xaPI0mevY%l~57cEW^F+ z)23|}8UhSB@d0fF1yZUkkSqslR8sn?F zv+}XHiweHf#9Y`uG0UhokgMpQq8WYNJMt%WhknhfaA&4`-wOMevlTRG62`qf01@P0 z6m~BLso!bEy>LuLNdEM90Ir-j>_#j5aDbn;kJ-q3r`@k&tRkH%zLGltuIN>{UnLAt zf9v-NjB|P-i(@5nQUh(EBY&_!l$i5MIkzFfNKm5(|JW}AbMV*y7-#Qu51=`j!U0VG zD&wr-{$zNx!)@mQo-8l}lHBS7+yS&RPnH0#6SeetV?=u(%WW2F0ER#62<-*WiQ}_L z2@$}IQ!p|vyfMAQjREPk=;;hX-6}zX1VcK}c(x|n^a;IqhIVHNw!jGIIp@r4-C|mDIj^e{QC~QE6mDeh<3849j>NR;W*5d zAbQcojPGK`Ya;@ZMtRu7pWwpYR!V!aE_#Q71wP5@BW!5VG_c!$8(zTKhMe2|p^L)! znX5i?P%a*nZA5TV?hSdLw24OCT&n^+pXivCp)UUgt2GR8AJK)a>|bOEz7;146ut7Y+ZKiPxEnxxN6x@a_R%^w`j$9j75P~+ienJz6TfR^ zaC)X|Y&DR6wF4ZsB6@WG*q!2Ppt8Ts?%2L8N_v7H#=VH5bWsegX{|5H90+cSjLl58 zunYY!V%OzJ5Y3D~UCtWRJqj69hi8ObUoe^lw5S%~=xjzpuqHw$^bPIM(!rB*AL~pQ zC5-Fa4i>_9DHkfrr7o4m*53j} ztx^7;#c4Upk@o`BdWN91S|4z&Z~Fo*PV|yxP8^d#>(~fZR(lu91!dJ(163?F)czki z&Q{ZRGwtodqEkE`6fM9Z@M8@Ea)QvSFcFtP0fC9c_?Gab*mgVcOs_0wA}%lycy3@K z9DK_f*>@i4i?iY6O^|X2U%WAMhjS8gg0IGcZ;-+CZUuVu`RbBgXnVaD~z8dvR0Z<<`s@7$j4Od%?Mr zZNeGkvMHf{-_G3ZWt&#<44ti^@wq4gKkJ)w=vCR-M=^qM4sAN6b7(X5H_JKns_a#( zIES=(T>QJxr;QnhTwt)oFf;@3mMKC z0BjJXHsBf?dw~f=b|`zIvDAOz8(;WFq;oKIz#al{={Xqe1CgQ!t7LXY9Aa~jiULKVC3r{B z>#|7^a{^s(gKa3`%2$uI)g)n&QuDuziJK|#k*&p@CCxYI)g}{bKY6 zbaST}NbA|WpV#CmG@gT3zZKe(N&h}YCroZNzy>Sk6K8_YE5y#DVtom{RS6bgB?he1 zUoK#Qrp9IE%3Z%YuwKyw)_QGj!>*Ug*-pzM1OD;YHj5m(WOzWbcM1#wPK!|Th;jku(B{dPf)G8B}7x+ z>T(wqHR?sZKwePzxZcRJjP-fEDkNodRqxmbC-ow?#G)S8yLaI}HnM#f9u>G$3a^gk z#L08&!lZ~E#ZtVUhX3f5a1K{R_lDKPDzuG_Ddh#Ujh&?1a9lA)?nQz`mh<@rHiJn? z;Hk}B3-+wz4U(ma7@di0KOb_z5xmCRw^HbkI(IUJ#;StYzz`EdP8Rqn+wWj)pcY>y z2_^;|6d6RA52)J~As|FZjA7FQ{y~vto(+r>@%v$i;G;`A*%CkEN|Cra2YMB4X}cEA zbt9@R*{i;*2s}HPfuWyWY?2t+@`iZYzRmX)rN}o{!wKRXM9;wAY8*1nPB-o$hm)3C zcpx#SdvPe7rg>kiPgd|IEg8shHrD~N9-W@kRtS{gB$fN-VOYmH8Y)N`U|fb3I;%;# z^*F~hr9ojNl&ednd?05B9 zF*+1dN+`}}KO}BMxM4mgilpJN^k+Aey&qzHXPc^L6RTewEj{lR1PWNsS=Z0;tY@!Q zn;rScmFCB));Sc=^Rwt(qU)!{pc|{t*x3rt0bVe=cF+K;?eJizth!EV)!{{s3MQjN zdzD4lVN;hp^RntV9cC}2(=lZ|Hmfd$*7Y3~Og%VPxgXwaxi0Gwm;2#qlrlc)t347l znsBpnKRkAoKB^gUp>|_em-av~EUdY(A6^^bW%qHRB5|sbRYz_KisZV2D&-_t zbs^uRvg!Afszo6PFJl`PMV3BUS_)?@;gWc9`q|b%9Zht%Ps`w@ z&|ty2Go;o;{AQjC_Xbm z6j?2jWhMx=u}qMjnINQx3RgO|u9XQwx@*7(x|0Wy3tMGr*iJqC|GN7Y__(Ta-~F2R zB$<>nP205H2?f$elF4(DltOlGOCz-{v=k8}on$8MG|5alne+i-(+7egQWS-Y2c>`r zf}$SI@r6*&0X%w8iWk(Q94P+q=)H%Z)Z+^k?EU}0wfA(Iw&F$a@7~`HO!r=EujjYE z^}W`&)>6%Yv?G(rlXlFaw4)FP(vCP_AQe!C4zxsDJY+MwAW(^@Lu|6=VH|x>zwtng zN6}9Y(dtblIA}_6zy&Wr6XK&7GYwaEK&D$@QbjI8ON>qexmU>Kr9|rXLgis2l+@}2 z6Y~SaJPKz}V?6(AgX*;psx>NfU9RCF2z8rrr&G7FT!<|LB1GK{8?frc>wvBvKoC6i^C?tV6REMOWV8n83h0=Yw~k@Cjhb zt$1<7KBd7Jh}DgI_+_5+Fynow;t>hQmIIQsyhhG19zzK$KfZf*NAyM3-kdMrsqBte zXOlOsuz(G|f&lG~|Lp{uD%o6-x1fb$F=X$7aNbol>>TtK@D_-%_|FH6A=wXk3&j{H zj;8bQe>^p_57UrSUoB}HMb-i{8O?-Ta%qqa!-fo_uoirSs0b|Pd9gTZ1;{T#4W7|D zVgvMkbW>14@dr{8!h);?V~2DRB!oef$O2Q1umP8~i08UzWW9g`_2-PNxBrbn17j*d zBg))g02?u(0!o0lV!Qu8!v^Le!sY?mq(me+CEfrI3U8wSFXK(0nv!bm4!8-778<}) ze+8jWfq}$ZmzBx9R%ZU=C7GDqv=y@?EKIbaB$G7AT`(xYWkkCraT`6aqNTO&0#Yr^ zIM{cIP?$o@Z4O_^!-Fx2jo6hEg+Wl(acE$Oe&0U&q;L#z_(RqZY{-Jndz(hu6@ie@|w98kmb z#VQ#tJmD%?Bytfl6%7YYjj{oVWC6psf}&1p!*xT~c7h)3SPV3<9LB|%DgYADLuFkqH6buUsgtq=h0i+gutgoif%0f1m#v0VkGrMmWdp@M@C{A05{Q;? z%7ptBC_X?Z$K2A%9>?6mLy{yG&ImY6B({nP+rf?Sh}Xkz3UOMzCu3kS5KbG}_48) z!T=FjM8+$IgH|Ph1lvGoL-v5Z@p=IGvIl60fhL#q0BKYYnCUO?gI#R9J+;jQ?bN1< z%>o}57*X2)cr-CmiM9+_R+F2@1)O=j`V60_h_pRj3rUKC@KL^q`xz#WGkG0Cw@|F6@!&u)L^gLPL$~r9Q%dNg2&oBi{9k@0a#ATR znejp)u;xq8R4#?qL2GAg;Yp6^3pK#C_JLFYz>={ZZGa7h!~#Tw#R(lD4a5h`dIKhk z*hU_-N7&#aCpF$6SuwsE@mPsNJY`T>ldEBT72+|dhzBn7&A^%>;%DHj52&`{rx>uS zP%E#p0X^oE6M0WH$ zE~*Eo!D%R%g9Vmi5BVpQjp!XD7 zs+9xebmj8EmI+ppVM0j&)pZ(%f%{=TxB&sU=qE0Mgb6ym&qF7M4jd235IT33L~sC| z&zD4Sv^f|FLfd>Q+>>QUR zN|*5mUB<5#@PYQ^><}3~N%aTVESkWdZ<6qiH*FF{DP??9LRoYxmN!tBNsWt)_}RNy zB`pbvz!g}eOFSP*-72Gc56x?&sKH{jOi&xr6DQqq*@xSq&{?1|semZNn7{14P=(^H z9`16fL8LK+as#%tl*aJ1F(Q#J4I`>&V1`w7K@zmJJ~|(xsN(K&b{4 z>kTqopqul`0dH1Gr(}1t01bcu2L1)=^-~AcV8i{iRK0!{(NwSh-cSm^?VaMNFVV@{ z&~Fk2U?d;{v5L zm_r16=$E2ayiB84{YUZJDmOG8)R3dc%R1`}2y3#kfxG{h0QrbFSMSiA5)S*(}L0Iu`$o8?%{@sd8%AjT1^(}4Hf{zfSY z#I?kt(xe%^wpoJNCYF%;@?;T6N7SGj7ciCkqP55oT@48Eh(IFc7Yoe38v)pfIdjTQ#5{a~y?0%oBV8@nf;be_k5(7=!5R-$%!7n zt(fRR_Z5le9j7*I4koUW?>W-3Dbr~ijG11VLy}Sp zo++`oL56gsbPOUh@P#v#Dw+UMLR#c;A1>NFeu4`C8NyjI$Zp1J>w~1?biXp4r;c3> zzaR(K>)G^WLF#0MFgSvwq3AwD z@YIpHQcpd|d|w&CfFH`iieBC^@+40%1cC;l{U(A~029?os2^?u74$;iXYo`|HW&p} zKxS5_c4A_kSe9f4&S98TW^6Zi9#pL@w#z`jyrL+&Lk&T5Y|CrVNrec}1=V2Vnbb=t zEeB_F+v(;Lp~h{)d$*wj5rLP@6SJf(BKD|*K~GWMaY%?>y0 zG2FQ#1`3Sfdz_sD6_|g`ZE)qomo%Z^$cI=(qypd3 z9AL=SSU<#-DoM{MW+OobS$i#r2?AooJuE(u4d`m5Q?N#3G7)c4sH@otPlt_z;0U zVWNxwh+NkWXowmu*JtsN2sT<(v$_na@qHL@kHF(pQAgD)9ZA41v{mQ~ch=zMJ{qr_ zdE11`^#iZ~i@#v|^AL{&h;msgcBVMu6pBm+GC`U17xI#IjIiaUn^8o_CK1D#Rsat; zikrNU+$<)~Lu#YQy|N6{QxFh^BI6{8pCB7vLG|zosh9DSxR{rEr{FBlV`nFMmJ*ND zTgKbf@rLt5$wm2!9ZlXVtQ*b}70b;{=c-qDT;q&A=jRWSMf2jjx=v#?%JtE5$n8md z`mqi7 zefG`Tpz7l$FI6Agu!@xEq>j2Jvl4WOkU%43YnPAi>#XkjH|?_OD63Nyb1R#wn4-xl zI*HK3;(4@N*?BA_w3FVDDq8L=rqNd}6O8eT5HS1`j0M2mp>^qsLE}qI?)BATa0sBz zhQvSyP_hU!ip~Qml7=-#6w486xYsfQ*q0%(Ffg$EI!y_>)TBr$osUAs0(zY&%2AgE zzcrLR2MR6HrjTW7jhG2o(c(?FFkX;MVi_H_D3sg_jRpHZbTKtc8I}l_JZQitk@Tjc zW?KuF9!um0oM{2#kBKGi*>^A6gZEOg1_?OHTywFT@E{XTX*jK3C>nG?3dHvwZ8lol zj%#T@MMMIGT%kLPH_e%iF{51>AjG{$^ZC?Z@dvq;U3e@l#+if^jhc}z*Z%Gh;H!ydOi0I_>s3$i-mau}HSK9>I-Zym7|fVrGv>00%`lXa0YRw8 zm|;VNw;M>nNm(6dIp{K)qSID6cPU7mC<$UrL<0t0(3XAgzwiI{D>vT%-CK8y4QkoG zKkogX554f{YrBXx?8~y3U-;&=2M%BR!Zj+vH-7i~pFj1HFFxZiffVul?|=X6uf6cg z8|aOSE-$Mc}Ut~np$ zbY29ifdkyw4!Y^E9eh8Nrn)n=$N~}=B5Nbo?a1Mr+W=BryAcp2*13Zrj+hV}=a$CZ9lxWM`ii#-8;W9}v zCU%d;>pF(GN_bEESRV(gCQgEUvMc_m-?d*pc z$P4LWAp(GRi|PhY{Q4V*H~^3_>TPXyr2z?aucahVW#%$qdSjQs^(l0kgbtT4$@$qB zGJVG5_55u}l<(2XB^2H69AOAV8Q=Wdi=WFJai}cKQ86`5u?VkBTuXscrfqiu+nl3P ztYeWBqwytHb~WzSd=0Jc1xz3>f~Z6BQ{w~WrT`6)UT1!IjL_H-gvW^C>>hXKZI_LB zVq3A;NpV5M!UV@2gptSq9KoQ1P?J<**@8t`bP`F3R|mjADW0nUx(!n_=pI0;Y{L9N z&gbe8YA=~3gN7kKzA=nll7@@wjM~6rd7Yb_jaCXW1rUJskb;ImmlITr8u`zOD!*%0 zR`8M{$tZyp%GOOjj`|=l2&sl@BA7!?C7AP&uA7hqxSI!Ui^*bVoqH8DYU2Ti*xCSJ zH#!t+b-D?Bv3+PXh73ahS%c>pQo)7b1?d@QCo(-Jhek2oCnxyr*}FeDB3my|5T_t~ zMO{^!nV}9q=*1Hm*x)+jq-qRRjTZTcPY(cV1#@|D4;mr{5VVB63`HY5AJp0nI^4ep zF4YbpkFH>UE%pyeHMo!s8ia;%6 za~sOB9Bnlu0)%M%so93&eN2eegJHPj3kVS#k~1--Hn3ReK4@X6Kth4}X$Q6|bAsey z#q2DnfRwHSCjPDR4UKiPGbaHFg9z#==FuYt+vJX;r~sO31Uk=!c-x0Y!`^D^s_Uh_ z-pXFf#8NGwl!;kFKV|d?DvyD}G5W>M``LL!oTBqUfm3!K{SIK$n(B9`;PqQ!3~&Of zpmZK|Qc8!AB1nh%alFSJ^XVK3)BVN z#G@F%u|qEGVJkZU_E1i^rKbpcDP6No>AZM$c-Thxm8OQ-MZq2#iGn>kDWEt14Cn>J zK@TA_IESA&MAEh*@|e#k-)+6u=mo8(jYOyZV54FS1BY!0xb&G=ARc>MWC!%>z^_P` zWv7VD25bpM1DIY8%4IoV8bA<4koRKwQkE`^*i5+}8LSXq?m}EKr?GR7qB)2&m`R0f z0;xEKlXj)psp`rc%p{{1{lvTyZ|#^}d2M|K_kUKLcK>Gu(pPXd0*=f&Y2yo`X$_$l z378N!gFxBCUD7n;Vkw)UimSK8n+j1vZxRxwk6IjXh7$5D{16=HO#dv;+iD=|5a zB4FKE%n0f~6tQRrsR4FzH*8EUm`A%fMP>gHhLOzzFyz#IT7I}bv=auSHKVWi;uA=a@B zYMxM@YfTYZtvX}@1&;EZp#ER+w2D~|sU}+60 zok=$uUQ>*Qyzd^ue3Cc&V9P9D-CcN^K9oz52W zyX>LdL^g$g^Y(ChSM!$KXu5ezJ~x`XDm|QRZW>JHH|Lu3>CKsOByJwh4>o7Asr1gK z!F;li9&gIz8aszt5~!CZDcHU`lviNq7YB91E|$ZFt9WM=`t|@1^NCBHU5(ona7* zVtR(pED7(ydlkG1t_4JYT<+C!U`nd5AUq$xLavZxi@bC{!h31!o=3Q}w=W`mPD%Qo zPD%f>De3=!a6?J@H}Kw65otS4~MDnG${lWtX=1D8i-C z`xU}VO6spe{?h)Rjqse3?~4#VyCmG1QJSx_oXZGm;)pj*em4F^PH|O^%IavYSV8gP;Pr z?9fDZkWbJM#P%1G1DH?w+*tomJ~^5mA5N#e*Ft7A-JeZnbK|KAP#EMUA(TItl`oN)IJ5C;LlUu#xj{1DcXQlMR~4W(w=2eO_z&Gbx#?BgujE$ZGxrP@rkq ziBbID&kXNS?a!n})1$e(P_ul&eILn;W(w?ee{N`KJT0$TbYoy5Gm=8tTax4b#STjV zX_;W00U?5@W+0uHa3(7;3J|MZc)8$1VaZe~pB^7)nhc7~jil14)d+YMAjwJ>xKaiB zksbxeP+K9HFGzLy^x#B(9H6wN>2^My9Ndyloiw^Vw%w54IhGzQfY>d-{Ravs=HVH^ zSTDpAXr*lw+*qI4S=hBQH<4eKDXdOsHy5@nPfPLX)Oyx@K|VJzwj!I7=Y}nrd|}sy z9XTXkm&=UjvY?o`yrz*NM)9k_k5rG8li}s4>+Se$#4n9s4!<4v4JNbMT)|Eb4gx54 z(%!HIok`h*+lalskjp1GyGUvSe}HQ?_*!zPkj~pFKqNmQXsGH!HPRpUtvNq2UKng1 zXzOZ8wIv5y6GMrvuA%Pkct=M|OFTZ<-rm|VFp%hKO|^EW5}l;h`6T&aAthX;Anj-- zhK-QD)C6MMT9oStz-HmeK6xCW4DZSD@pPWpZ4V`Z9jP9BJUuehluwT)Gg&mdVS#<# zQoH4E!W0K~fl-4IcesprU}C5lzy1v7EZh1J+DdLg8WY0P!;90f!ha>+{2zlwAvv4|98MmR!EC`kcc~f~L2XU@8v3>geYpug!it=G za7$-9;kYiO`j75%y{{O)#!c&ezZ>By{7#4a??D}V@%s>dci{JF{2s!ObA*3{E#(K+ zF%3V`ZBJ_XA==;^g%BNirFw04Fl}c*bCY}l?Xk!5>Ft@^#Q4ZAdmx?8+G8>m(-{1t z$VdK_%cdJif{`y%$bfZRB{bL`P42Qe@dna1=qiN8QIH6iu53?_?3y2riL~+8&ZF^N z*}>)<+6#cDQ08j1i4s~Xe(u~asTFi!+XQ*j=tLpC^AOV8NcUGy=J8$Q&11=t<{ioL z(dMS6=85e1#MoFa53NJq2kP94Dmk8SW$xs$I?wUD7EjKd19){3_(h{J zts1|%_<8MnGdW`nY1!YD$17~GM(_?hy>l>~M$4ymd?H)qNNK1ko5@uu&AbUuI}Ppf z0H^&I+Clk+3Aodnt@-^UY;2r8v)jnN~S4ksELqI7bfyqAV0)@(K0YbUJFNd zX*I~pKaL^Gf2;EW3P)~GIExx_;##3Brd^0K+rTKPu?Pzdhrw+JhkL^K+mO$oVTGJM zz6Gprm~TmY1PUB5X)rmK9LyAUA>T_VhcfnG-?n^mNB{QpAQ~4dS9A3+I?j1Op6Bs9 zYB8nZT7;LUiKo&7@a4gLW{k{G$+X^hP~HXc8XU%xnuix}+f`OE) zq%~V0sm3lhWZS|FU8allucF-?cdH@>!<(i}P9NPi6e=aQ=&80F!yX?Xi zkVPt+HkD0#2i5+0@frv5-3 zgfbIhyfQe)N`8g;~()fj^C=}_!dknh~-60v2)uM?Wv8aHVM8o zr_y8N&0r>52J*QbSt{1;O>Kgyz=mc3gs7_ZA`k1Q7RWZrh~U|RpEr)A>23Ix!sIyK zAIB{Zb&Cx`o-d<(^1r`x+qMMoA>U2XkTIGpKy?Aw^T|x%O((EuvB)a0=)}_-pW|&A z8ZDq#4V4N9GN{W&x>q0jdNJ)_E}s@4AgK$41x*0-81f*w7H?^7Ywzexbaf{O2BEWT zKs^6?F86E;Yh?yZwJq42)_^5@wgpY|^4)^`96Rr+aEN57VE2GNES1t#pU%U(*lg_F zM8U=+7@);xyhqR$6D}u}X*-O?w@6;Gxw{i;0}EbZOmEfEKDliLA6~Bt2BH z?R;kQmck}?UWIK?^`SzK9aix@wss-PV2>}ylk_!@C-M8ljLhL?#Wyd{EpFa>+&o@h z6kCMHVSFQ;&&SWhuU@=6_$|ZF=HJ!!V*C?c9L8HylYPx%`M0Sle2slgLj&U9?G612 z!wF>#qaWXS<{2@u$Yf9+`w)k*E8ZG!i?_!+;+^qCyer<_5^rf~X>Dn1X>aLh>1;`~ zbhUK1##>ujTU*;&p+mHGwkBG;TD#lgZ7prBZEbDsZ5?f$ZHcz7w(j!?B%s}gJml4n;z_!#|6l&ooKHLep}Woa zvw!B4KZ}2w_KivUOg<~1frs{7xN!LdJdD9{-pT@>Bi$3hme-276n}+%Q`77>@pM@ zn#X9GBC8TkqrHNBWdB50l5Z~zDk$s^I=F7?mf;Hoj9@TignbdC+=}Uy#x&m!atkyRtI8UFiZ?%Svhs-Y+j~GuI<}}p9_88_<`{w{fO@+<7d{-jbGSDt=Eh{ zn19rx=PWsI&Dxtj@rh4feZxmScGnlb`o1st1EJ2P=WYDe;b*L>n$E<=OLu?fa}RyJ zVk4gC7`W9v8E{_&>fa~dwW29`{G0)93V@ zzv7~MKmF8q?hMSFRe#ob=l|@LSC2jMq-CFZ*4YhhT|KMbzIxsIOE$jqT~}PWX)rxB zJihaq-5ZZ>>de_by|>G{(AR8*1ED~#eU23kb(%fC zSph2=Sl5?mD{Bih1;cyJzWBmL!G+bc&aSPR5n6)^mY2;8g#D|6=Y%FA%g$TqU*Ze< zFY@cYnCY9mVPNj6V0iN0E9+N8!v3-|di>$e#nz0;ubi7&A6*p+uUs*ERd9V-Um!gB z+m+!t<^_ETvpg8~cL&0II%fu!n6(@Aiq^7yA0L{COg{dB)q`dG#Pt<1e>@dp`JnYuHz2 zh61qO$ulg7s_mY>3W5TRMZ~NE!-E{_9!c{eDe1 zeLlb62>646P-VC_GBY}>ELI+^uwv%4X=jA0^%+);KGU2Pn61|u^RR7yk=Yn&(&J`} z(W-yixZn7U^+50s#vgre7=JR4g+9A;*9|w`6~FYIH+=9w?Z1~-T)6s=uQxTHf5p4| zf3p9^58eFX`@itjuRZbPx4!+t%RfD)S%T1so+V5B-u~|WAHv6nzxuT&zx~~(U;Zh! z4!Y>Rg!q1CD!u>akKggF?>=2txu9psioQ!Pzv9aNRQkr7??;v=zV+hEKRsGjxuP$X zp4|V%M;?9bxgQ+;<-TigxaZzSAA91PPygu0t8V-Hcb@$2(|v2!UV7P;{qO(KO<(xO zFFp2+C%^fF%IX=HU-8@D{pr}`=(ZPLET5On)z0a^=DnYLX!qA1sh%-+-pUKstR?=x zclSR$@$7TYAN}QT^5ZuZCO&p{Q}d@E`qE?HeEJ73-rjrbZSkAteec=t9$T~aU6%)f z6|r-gfAMNImsooKvK0qzUcY(bU%qwtnIHb!&;E2wv-|7!zG&@T9-M9YEB8EDKKX!e zUTDv3b7oMtnyq##VCn&XpfbF!Vp`ymfN9l+LuSwnmNe?=UCt37%_KnCAw%f{T26k5$$Ln=2d5x{A7r$q!n4 zZ=D&Le*G=JX5SKET1{y3(fUGk^8485HF?Z8`C|0H?l2RfJy%psemOY#ufA~25;N@Y z3a$)B{e{R}^Ig_up~-zUwc+Z}YHRWX{s-=f&ahezT6=zUb|C8WP2L;Z^P7NfFZAQ< zjn?F&=4`W~?6fr8rRDv!V1SH&zBVRm!aC4wstaED3cQnloKy~U#^e|oz!ei$%oiG z=ISoKUHKN7=LQ$n=yn1btRTiZ5H{xM z*tf15RuD zN2#U{SQjuNQYxE-N)3i)TDs2&>uGR_`DV?j<8Q}2u0y3fdpn3J|d&p6Euw5Oxz0=V1=gfWUr?GbDd`1 zsBf}0Kh!fz58K8%1GEuspK18?Ta8)M%Jj2?Gb2rA9DOs4bM&_X@&?>3gL<>xhEff~ zhkh?Kg8DBAHXZs^4B911`HB8fpJt+$R)cBjpF;VXvCdo>X|b->J1Z8TpJB5FWd`)6 z=6s(XJP+Ga+Cw1tdcR3f0x0?&x*41>UL7B*D z#;SA;qucKD@lE$vXdnZce!g`P;Fws8PD!RB;! z8seI|TkM9Rbl1QjG?{?~+TseRB%9NP{-Jad2D literal 83701 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 diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts index e5ed0a30..10694398 100644 --- a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts +++ b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm.d.ts @@ -1,9 +1,9 @@ /* tslint:disable */ /* eslint-disable */ export const memory: WebAssembly.Memory; -export function merge_tree(a: number, b: number, c: number, d: number, e: number): void; -export function export_tree(a: number, b: number, c: number, d: number): void; -export function tree2Bin(a: number, b: number, c: number): void; +export function merge_prof(a: number, b: number, c: number, d: number, e: number): void; +export function merge_tree(a: number, b: number, c: number): void; +export function export_tree(a: number, b: number): void; export function drop_tree(a: number): void; export function init_panic_hook(): void; export function __wbindgen_malloc(a: number, b: number): number; diff --git a/pyroscope/pprof-bin/src/ch64.rs b/pyroscope/pprof-bin/src/ch64.rs new file mode 100644 index 00000000..eb11e98c --- /dev/null +++ b/pyroscope/pprof-bin/src/ch64.rs @@ -0,0 +1,181 @@ + +pub fn read_uint64_le(bytes: &[u8]) -> (u64) { + let mut res: u64 = 0; + for i in 0..8 { + res |= (bytes[i] as u64) << (i * 8); + } + res +} + +const kMul: u64 = 0x9ddfea08eb382d69; + +pub fn hash_128_to_64(l: u64, h: u64) -> u64 { + let mut a = (l ^ h).wrapping_mul(kMul); + a ^= (a >> 47); + let mut b = (h ^ a).wrapping_mul(kMul); + b ^= (b >> 47); + b = b.wrapping_mul(kMul); + b +} + +const k0: u64 = 0xc3a5c85c97cb3127; +const k2: u64 = 0x9ae16a3b2f90404f; +const k1: u64 = 0xb492b66fbe98f273; +const k3: u64 = 0xc949d7c7509e6557; +fn ch16(u: u64, v: u64) -> u64 { + hash_128_to_64(u, v) +} + +fn rot64(val: u64, shift: usize) -> u64 { + if shift == 0 { + return val + } + return (val >> shift) | val<<(64-shift) +} + +fn shiftMix(val: u64) -> u64 { + return val ^ (val >> 47) +} + +fn hash16(u: u64, v: u64) -> u64 { + hash_128_to_64(u, v) +} + +fn fetch32(p: &[u8]) -> u32 { + let mut res: u32 = 0; + for i in 0..4 { + res |= (p[i] as u32) << (i * 8); + } + res +} + +fn ch33to64(s: &[u8], length: usize) -> u64 { + let mut z = read_uint64_le(&s[24..]); + let mut a = read_uint64_le(&s) + + (length as u64+read_uint64_le(&s[length-16..])).wrapping_mul(k0); + let mut b = rot64(a+z, 52); + let mut c= rot64(a, 37); + a += read_uint64_le(&s[8..]); + c += rot64(a, 7); + a += read_uint64_le(&s[16..]); + let vf= a + z; + let vs= b + rot64(a, 31) + c; + + a = read_uint64_le(&s[16..]) + read_uint64_le(&s[length-32..]); + z = read_uint64_le(&s[length-8..]); + b = rot64(a+z, 52); + c = rot64(a, 37); + a += read_uint64_le(&s[length-24..]); + c += rot64(a, 7); + a += read_uint64_le(&s[length-16..]); + + let wf= a + z; + let ws= b + rot64(a, 31) + c; + let r= shiftMix((vf+ws).wrapping_mul(k2) + (wf+vs).wrapping_mul(k0)); + return shiftMix(r.wrapping_mul(k0)+vs).wrapping_mul(k2) +} + +fn ch17to32(s: &[u8], length: usize) -> u64 { + let a = read_uint64_le(s).wrapping_mul(k1); + let b= read_uint64_le(&s[8..]); + let c= read_uint64_le(&s[length-8..]).wrapping_mul(k2); + let d= read_uint64_le(&s[length-16..]).wrapping_mul(k0); + return hash16( + rot64(a-b, 43)+rot64(c, 30)+d, + a+rot64(b^k3, 20)-c+(length as u64), + ) +} + +fn ch0to16(s: &[u8], length: usize) -> u64 { + if length > 8 { + let a = read_uint64_le(s); + let b= read_uint64_le(&s[length-8..]); + return ch16(a, rot64(b+(length as u64), (length))) ^ b; + } + if length >= 4 { + let a = (fetch32(s) as u64); + return ch16((length as u64)+(a<<3), (fetch32(&s[length-4..]) as u64)); + } + if length > 0 { + let a = s[0]; + let b = s[length>>1]; + let c= s[length-1]; + let y = (a as u32) + ((b as u32) << 8); + let z = (length as u32) + ((c as u32) << 2); + return shiftMix( + (y as u64).wrapping_mul(k2)^ + (z as u64).wrapping_mul(k3)) + .wrapping_mul(k2); + } + return k2 +} + +fn weakHash32Seeds(w: u64, x: u64, y: u64, z: u64, _a: u64, _b: u64) -> (u64, u64) { + let mut a = _a + w; + let mut b = rot64(_b+a+z, 21); + let c = a; + a += x; + a += y; + b += rot64(a, 44); + return (a+z, b+c) +} + +// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. +fn weakHash32SeedsByte(s: &[u8], a: u64, b: u64) -> (u64, u64) { + _ = s[31]; + return weakHash32Seeds( + read_uint64_le(&s[0..0+8]), + read_uint64_le(&s[8..8+8]), + read_uint64_le(&s[16..16+8]), + read_uint64_le(&s[24..24+8]), + a, + b, + ); +} + +fn nearestMultiple64(b: &[u8]) -> usize { + return ((b.len()) - 1) & !63; +} + +// CH64 returns ClickHouse version of Hash64. +pub fn city_hash_64(s: &[u8]) -> u64 { + let length = s.len(); + if length <= 16 { + return ch0to16(s, length) + } + if length <= 32 { + return ch17to32(s, length) + } + if length <= 64 { + return ch33to64(s, length) + } + + let x= read_uint64_le(s); + let y= read_uint64_le(&s[length-16..]) ^ k1; + let mut z = read_uint64_le(&s[length-56..]) ^ k0; + + let mut v= weakHash32SeedsByte(&s[length-64..], (length as u64), y); + let mut w= weakHash32SeedsByte(&s[length-32..], (length as u64).wrapping_mul(k1), k0); + z += shiftMix(v.1).wrapping_mul(k1); + let mut x = rot64(z+x, 39).wrapping_mul(k1); + let mut y = rot64(y, 33).wrapping_mul(k1); + // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. + let mut _s = &s[..nearestMultiple64(s)]; + while _s.len() > 0 { + x = rot64(x+y+v.0+read_uint64_le(&s[16..]), 37).wrapping_mul(k1); + y = rot64(y+v.1+read_uint64_le(&s[48..]), 42).wrapping_mul(k1); + x ^= w.1; + y ^= v.0; + + z = rot64(z^w.0, 33); + v = weakHash32SeedsByte(s, v.1.wrapping_mul(k1), x+w.0); + w = weakHash32SeedsByte(&s[32..], z+w.1, y); + (z, x) = (x, z); + _s = &_s[64..]; + } + return ch16( + ch16(v.0, w.0)+shiftMix(y).wrapping_mul(k1)+z, + ch16(v.1, w.1)+x, + ); +} + diff --git a/pyroscope/pprof-bin/src/lib.rs b/pyroscope/pprof-bin/src/lib.rs index 10e5eb22..db4aa681 100644 --- a/pyroscope/pprof-bin/src/lib.rs +++ b/pyroscope/pprof-bin/src/lib.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments)] mod utils; +mod ch64; use lazy_static::lazy_static; use pprof_pb::google::v1::Function; @@ -13,7 +14,9 @@ use std::collections::HashMap; use std::sync::Mutex; use std::vec::Vec; use wasm_bindgen::prelude::*; -use cityhash::cityhash_1::city_hash_64; +use ch64::city_hash_64; +use ch64::read_uint64_le; +use ch64::hash_128_to_64; pub mod pprof_pb { @@ -50,17 +53,9 @@ struct Tree { max_self: i64, } -fn hash_128_to_64(l: u64, h: u64) -> u64 { - let kMul: u64 = 0x9ddfea08eb382d69; - let mut a = (l ^ h) * kMul; - a ^= (a >> 47); - let mut b = (h ^ a) * kMul; - b ^= (b >> 47); - b *= kMul; - b -} -unsafe fn merge(tree: &mut Tree, p: &Profile) { + +fn merge(tree: &mut Tree, p: &Profile) { let mut functions: HashMap = HashMap::new(); for f in p.function.iter() { functions.insert(f.id, &f); @@ -141,24 +136,16 @@ fn read_uleb128(bytes: &[u8]) -> (usize, usize) { (result, shift) } -fn read_uint64(bytes: &[u8]) -> (u64) { - let mut res: u64 = 0; - for i in 0..8 { - res |= (bytes[i] as u64) << (i * 8); - } - res -} - -unsafe fn bfs(t: &Tree, res: &mut Vec) { +fn bfs(t: &Tree, res: &mut Vec) { let mut total: u64 = 0; for i in t.nodes.get(&(0u64)).unwrap().iter() { total += i.total; } let mut lvl = Level::default(); - lvl.values.extend([0, total, 0, 0]); + lvl.values.extend([0, total as i64, 0, 0]); res.push(lvl); let totalNode: TreeNodeV2 = TreeNodeV2 { @@ -187,19 +174,18 @@ unsafe fn bfs(t: &Tree, res: &mut Vec) { } let mut totalSum: u64 = 0; for n in opt.unwrap().iter() { - let current_prepend = (prepend_map.get(&n.node_id).unwrap_or(&0u64) + prepend); - prepend = 0; - prepend_map.insert(n.node_id, current_prepend); + prepend_map.insert(n.node_id, prepend); refs.push(n); totalSum += n.total; lvl.values.extend( [ - current_prepend as i64, + prepend as i64, n.total as i64, n.slf as i64, - t.names[&n.fn_id] as i64 + t.names_map[&n.fn_id] as i64 ] ); + prepend = 0; } prepend += parent.slf; } @@ -212,8 +198,7 @@ lazy_static! { static ref CTX: Mutex> = Mutex::new(HashMap::new()); } -fn upsert_tree(id: u32) { - let mut ctx = CTX.lock().unwrap(); +fn upsert_tree(ctx: &mut HashMap, id: u32) { if !ctx.contains_key(&id) { ctx.insert( id, @@ -229,9 +214,9 @@ fn upsert_tree(id: u32) { } #[wasm_bindgen] -pub unsafe fn merge_prof(id: u32, bytes: &[u8], sample_type: String) { - upsert_tree(id); +pub fn merge_prof(id: u32, bytes: &[u8], sample_type: String) { let mut ctx = CTX.lock().unwrap(); + upsert_tree(&mut ctx, id); let mut tree = ctx.get_mut(&id).unwrap(); tree.sample_type = sample_type; @@ -239,21 +224,22 @@ pub unsafe fn merge_prof(id: u32, bytes: &[u8], sample_type: String) { merge(&mut tree, &prof); } -pub unsafe fn merge_tree(id: u32, bytes: &[u8]) { - upsert_tree(id); +#[wasm_bindgen] +pub fn merge_tree(id: u32, bytes: &[u8]) { let mut ctx = CTX.lock().unwrap(); + upsert_tree(&mut ctx, id); let mut tree = ctx.get_mut(&id).unwrap(); let mut size = 0; let mut offs = 0; (size, offs) = read_uleb128(bytes); for _i in 0..size { - let id = read_uint64(&bytes[offs..]); + let id = read_uint64_le(&bytes[offs..]); offs += 8; let mut _offs: usize = 0; let mut _size: usize = 0; (_size, _offs) = read_uleb128(&bytes[offs..]); offs += _offs; - if tree.names_map.contains_key(&id) { + if !tree.names_map.contains_key(&id) { tree.names.push(String::from_utf8_lossy(&bytes[offs..offs + _size]).to_string()); tree.names_map.insert(id, tree.names.len() - 1); } @@ -264,21 +250,21 @@ pub unsafe fn merge_tree(id: u32, bytes: &[u8]) { (size, _offs) = read_uleb128(&bytes[offs..]); offs += _offs; for _i in 0..size { - let parent_id = read_uint64(&bytes[offs..]); + let parent_id = read_uint64_le(&bytes[offs..]); offs += 8; - let fn_id = read_uint64(&bytes[offs..]); + let fn_id = read_uint64_le(&bytes[offs..]); offs += 8; - let node_id = read_uint64(&bytes[offs..]); + let node_id = read_uint64_le(&bytes[offs..]); offs += 8; - let slf = read_uint64(&bytes[offs..]); + let slf = read_uint64_le(&bytes[offs..]); offs += 8; - let total = read_uint64(&bytes[offs..]); + let total = read_uint64_le(&bytes[offs..]); if tree.max_self < slf as i64 { tree.max_self = slf as i64; } offs += 8; - if tree.contains_key(&parent_id) { - tree.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + if tree.nodes.contains_key(&parent_id) { + tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { fn_id, parent_id, node_id, @@ -286,8 +272,8 @@ pub unsafe fn merge_tree(id: u32, bytes: &[u8]) { total }) } else { - tree.insert(parent_id, Vec::new()); - tree.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + tree.nodes.insert(parent_id, Vec::new()); + tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { fn_id, parent_id, node_id, @@ -299,7 +285,7 @@ pub unsafe fn merge_tree(id: u32, bytes: &[u8]) { } #[wasm_bindgen] -pub unsafe fn export_tree(id: u32, sample_type: String) -> Vec { +pub fn export_tree(id: u32) -> Vec { let mut ctx = CTX.lock().unwrap(); let mut res = SelectMergeStacktracesResponse::default(); if !ctx.contains_key(&id) { @@ -310,7 +296,7 @@ pub unsafe fn export_tree(id: u32, sample_type: String) -> Vec { fg.names = tree.names.clone(); fg.max_self = tree.max_self; fg.total = 0; - for n in tree.get(&(0u64)).unwrap().iter() { + for n in tree.nodes.get(&(0u64)).unwrap().iter() { fg.total += n.total as i64; } bfs(tree, &mut fg.levels); @@ -319,7 +305,7 @@ pub unsafe fn export_tree(id: u32, sample_type: String) -> Vec { } #[wasm_bindgen] -pub unsafe fn drop_tree(id: u32) { +pub fn drop_tree(id: u32) { let mut ctx = CTX.lock().unwrap(); if ctx.contains_key(&id) { ctx.remove(&id); @@ -330,13 +316,3 @@ pub unsafe fn drop_tree(id: u32) { pub fn init_panic_hook() { console_error_panic_hook::set_once(); } - -#[cfg(test)] -mod tests { - use cityhash::cityhash_1::city_hash_64; - - #[test] - fn it_works() { - print!("{}", city_hash_64(b"123")) - } -} diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index 14fe69f8..af7db697 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -321,10 +321,16 @@ const selectMergeStacktracesV2 = async (req, res) => { req.log.debug(`selectMergeStacktraces: profiles downloaded: ${binData.length / 1025}kB in ${Date.now() - start}ms`) require('./pprof-bin/pkg/pprof_bin').init_panic_hook() start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 - const resp = pprofBin.tree2Bin(binData) - const exportTreeLat = (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start - req.log.debug(`export_tree: ${exportTreeLat / BigInt(1000000)}ms`) - return res.code(200).send(Buffer.from(resp)) + const _ctxIdx = ++ctxIdx + try { + pprofBin.merge_tree(_ctxIdx, binData) + const resp = pprofBin.export_tree(_ctxIdx) + const exportTreeLat = (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start + req.log.debug(`export_tree: ${exportTreeLat / BigInt(1000000)}ms`) + return res.code(200).send(Buffer.from(resp)) + } finally { + try { pprofBin.drop_tree(_ctxIdx) } catch (e) {} + } } const selectSeries = async (req, res) => { From 5526503e59438eb2a4e28322572d6447766db923 Mon Sep 17 00:00:00 2001 From: akvlad Date: Wed, 14 Feb 2024 21:46:24 +0200 Subject: [PATCH 06/12] fix: debug backwards compatibility --- lib/db/maintain/scripts.js | 5 +- parser/registry/parser_registry/drop.js | 2 +- pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 80195 -> 90471 bytes pyroscope/pprof-bin/src/lib.rs | 110 +++++++++++++++++----- pyroscope/pyroscope.js | 63 +++++++++++-- 5 files changed, 148 insertions(+), 32 deletions(-) diff --git a/lib/db/maintain/scripts.js b/lib/db/maintain/scripts.js index 520428f8..fb506879 100644 --- a/lib/db/maintain/scripts.js +++ b/lib/db/maintain/scripts.js @@ -422,7 +422,10 @@ module.exports.profiles = [ functions FROM profiles_input`, - 'DROP TABLE IF EXISTS profiles_mv_bak {{{OnCluster}}}' + 'DROP TABLE IF EXISTS profiles_mv_bak {{{OnCluster}}}', + + "INSERT INTO settings (fingerprint, type, name, value, inserted_at) VALUES (cityHash64('profiles_v2'), 'update', " + + "'profiles_v2', toString(toUnixTimestamp(NOW())), NOW())" ] module.exports.profiles_dist = [ diff --git a/parser/registry/parser_registry/drop.js b/parser/registry/parser_registry/drop.js index f98e2fcc..09a1d978 100644 --- a/parser/registry/parser_registry/drop.js +++ b/parser/registry/parser_registry/drop.js @@ -44,4 +44,4 @@ const viaStream = (token, query) => { module.exports = { viaClickhouseQuery, viaStream -} \ No newline at end of file +} diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index a399682f0e08aec3e84fba8d1ab28bd1a8f2f9dc..2de0f473c9c577d8a5175f828a9874098ac0fa5e 100644 GIT binary patch delta 40899 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 delta 31552 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 -> i32 { + let mut n: i32 = -1; + for c in 0..nodes.len() { + let _c = &nodes[c]; + if _c.node_id == id { + n = c as i32; + break; + } + } + n +} fn merge(tree: &mut Tree, p: &Profile) { let mut functions: HashMap = HashMap::new(); @@ -96,9 +107,8 @@ fn merge(tree: &mut Tree, p: &Profile) { let mut parent_id: u64 = 0; for i in (0..s.location_id.len()).rev() { let location = locations[&s.location_id[i]]; - let name_hash = city_hash_64( - p.string_table[functions[&location.line[0].function_id].name as usize].as_bytes() - ); + let name = &p.string_table[functions[&location.line[0].function_id].name as usize]; + let name_hash = city_hash_64(name.as_bytes()); let node_id = hash_128_to_64(parent_id, name_hash); if !tree.nodes.contains_key(&parent_id) { tree.nodes.insert(parent_id, Vec::new()); @@ -110,13 +120,21 @@ fn merge(tree: &mut Tree, p: &Profile) { if tree.max_self < slf as i64 { tree.max_self = slf as i64; } - tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { - parent_id, - fn_id: name_hash, - node_id, - slf, - total: s.value[u_value_idx] as u64 - }); + let mut children = tree.nodes.get_mut(&parent_id).unwrap(); + let n = find_node(node_id, children); + if n == -1 { + children.push(TreeNodeV2 { + parent_id, + fn_id: name_hash, + node_id, + slf, + total: s.value[u_value_idx] as u64 + }); + } else { + children.get_mut(n as usize).unwrap().total += s.value[u_value_idx] as u64; + children.get_mut(n as usize).unwrap().slf += slf; + } + parent_id = node_id; } } @@ -138,7 +156,6 @@ fn read_uleb128(bytes: &[u8]) -> (usize, usize) { - fn bfs(t: &Tree, res: &mut Vec) { let mut total: u64 = 0; for i in t.nodes.get(&(0u64)).unwrap().iter() { @@ -157,9 +174,13 @@ fn bfs(t: &Tree, res: &mut Vec) { }; let mut prepend_map: HashMap = HashMap::new(); + let mut reviewed: HashSet = HashSet::new(); + let mut refs: Vec<&TreeNodeV2> = vec![&totalNode]; let mut refLen: usize = 1; + let mut i = 0; while refLen > 0 { + i+=1; let mut prepend: u64 = 0; let _refs = refs.clone(); refs.clear(); @@ -174,6 +195,12 @@ fn bfs(t: &Tree, res: &mut Vec) { } let mut totalSum: u64 = 0; for n in opt.unwrap().iter() { + if reviewed.contains(&n.node_id) { + // PANIC!!! WE FOUND A LOOP + return; + } else { + reviewed.insert(n.node_id); + } prepend_map.insert(n.node_id, prepend); refs.push(n); totalSum += n.total; @@ -182,7 +209,7 @@ fn bfs(t: &Tree, res: &mut Vec) { prepend as i64, n.total as i64, n.slf as i64, - t.names_map[&n.fn_id] as i64 + *t.names_map.get(&n.fn_id).unwrap_or(&1) as i64 ] ); prepend = 0; @@ -203,7 +230,7 @@ fn upsert_tree(ctx: &mut HashMap, id: u32) { ctx.insert( id, Tree { - names: vec!["total".to_string()], + names: vec!["total".to_string(), "n/a".to_string()], names_map: HashMap::new(), nodes: HashMap::new(), sample_type: "".to_string(), @@ -264,13 +291,20 @@ pub fn merge_tree(id: u32, bytes: &[u8]) { } offs += 8; if tree.nodes.contains_key(&parent_id) { - tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { - fn_id, - parent_id, - node_id, - slf, - total - }) + let n = find_node(node_id, tree.nodes.get(&parent_id).unwrap()); + if n != -1 { + tree.nodes.get_mut(&parent_id).unwrap().get_mut(n as usize).unwrap().total += total; + tree.nodes.get_mut(&parent_id).unwrap().get_mut(n as usize).unwrap().slf += slf; + } else { + tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { + fn_id, + parent_id, + node_id, + slf, + total + }) + } + } else { tree.nodes.insert(parent_id, Vec::new()); tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { @@ -292,6 +326,9 @@ pub fn export_tree(id: u32) -> Vec { return res.encode_to_vec(); } let tree = ctx.get(&id).unwrap(); + if tree.nodes.len() == 0 { + return res.encode_to_vec(); + } let mut fg = FlameGraph::default(); fg.names = tree.names.clone(); fg.max_self = tree.max_self; @@ -316,3 +353,32 @@ pub fn drop_tree(id: u32) { pub fn init_panic_hook() { console_error_panic_hook::set_once(); } + +#[cfg(test)] +mod tests { + use std::fs; + use wasm_bindgen::exports; + use crate::read_uleb128; + use crate::merge_prof; + use crate::merge_tree; + use crate::export_tree; + + #[test] + fn it_works() { + let _contents = fs::read("/home/hromozeka/QXIP/qryn/test.dat") + .expect("Failed to read file"); + let contents = _contents.as_slice(); + let (legSize, shift) = read_uleb128(&contents); + let mut ofs = shift; + print!("{}", legSize); + for i in 0..legSize { + let (size, shift) = read_uleb128(&contents[ofs..]); + ofs += shift; + merge_prof(0, &contents[ofs..ofs + size], "cpu:nanoseconds".to_string()); + ofs += size; + } + //export_tree(0); + merge_tree(0, &contents[ofs..]); + export_tree(0); + } +} diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index af7db697..621f3ea8 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -2,7 +2,7 @@ const messages = require('./querier_pb') const types = require('./types/v1/types_pb') const services = require('./querier_grpc_pb') const clickhouse = require('../lib/db/clickhouse') -const { DATABASE_NAME } = require('../lib/utils') +const { DATABASE_NAME, checkVersion } = require('../lib/utils') const Sql = require('@cloki/clickhouse-sql') const compiler = require('../parser/bnf') const { readULeb32 } = require('./pprof') @@ -248,7 +248,6 @@ const selectMergeStacktraces = async (req, res) => { } const selectMergeStacktracesV2 = async (req, res) => { - const dist = clusterName ? '_dist' : '' const typeRegex = parseTypeId(req.body.getProfileTypeid()) const sel = req.body.getLabelSelector() @@ -258,6 +257,7 @@ const selectMergeStacktracesV2 = async (req, res) => { const toTimeSec = req.body && req.body.getEnd() ? Math.floor(parseInt(req.body.getEnd()) / 1000) : Math.floor(Date.now() / 1000) + const v2 = checkVersion('profiles_v2', (fromTimeSec - 3600) * 1000) const idxSelect = (new Sql.Select()) .select('fingerprint') .from(`${DATABASE_NAME()}.profiles_series_gin`) @@ -270,7 +270,8 @@ const selectMergeStacktracesV2 = async (req, res) => { ) ).groupBy('fingerprint') labelSelectorQuery(idxSelect, sel) - const rawReq = (new Sql.Select()) + const withIdxSelect = new Sql.With('idx', idxSelect, !!clusterName) + const rawReq = (new Sql.Select()).with(withIdxSelect) .select([ new Sql.Raw(`arrayMap(x -> (x.1, x.2, x.3, (arrayFirst(y -> y.1 == ${Sql.quoteVal(`${typeRegex.sampleType}:${typeRegex.sampleUnit}`)}, x.4) as af).2, af.3), tree)`), 'tree' @@ -280,7 +281,7 @@ const selectMergeStacktracesV2 = async (req, res) => { Sql.And( Sql.Gte('timestamp_ns', new Sql.Raw(Math.floor(fromTimeSec) + '000000000')), Sql.Lte('timestamp_ns', new Sql.Raw(Math.floor(toTimeSec) + '000000000')), - new Sql.In('fingerprint', 'IN', idxSelect) + new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxSelect)) )) if (process.env.ADVANCED_PROFILES_MERGE_LIMIT) { rawReq.orderBy(['timestamp_ns', 'desc']).limit(parseInt(process.env.ADVANCED_PROFILES_MERGE_LIMIT)) @@ -299,15 +300,44 @@ const selectMergeStacktracesV2 = async (req, res) => { [new Sql.Raw('groupUniqArray(raw.functions)'), 'functions2'] ).from(new Sql.WithReference(withRawReq)).join('raw.functions', 'array') + let brackLegacy = (new Sql.Select()).select( + [new Sql.Raw('[]::Array(String)'), 'legacy'] + ) + let withLegacy = null + if (!v2) { + const legacy = (new Sql.Select()).with(withIdxSelect) + .select('payload') + .from(`${DATABASE_NAME()}.profiles${dist}`) + .where( + Sql.And( + Sql.Gte('timestamp_ns', new Sql.Raw(Math.floor(fromTimeSec) + '000000000')), + Sql.Lte('timestamp_ns', new Sql.Raw(Math.floor(toTimeSec) + '000000000')), + new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxSelect)), + Sql.Eq(new Sql.Raw('empty(tree)'), 1) + )) + if (process.env.ADVANCED_PROFILES_MERGE_LIMIT) { + legacy.orderBy(['timestamp_ns', 'desc']).limit(parseInt(process.env.ADVANCED_PROFILES_MERGE_LIMIT)) + } + withLegacy = new Sql.With('legacy', legacy, !!clusterName) + brackLegacy = (new Sql.Select()) + .select([new Sql.Raw('groupArray(payload)'), 'payloads']) + .from(new Sql.WithReference(withLegacy)) + } + brackLegacy = new Sql.Raw(`(${brackLegacy.toString()})`) const brack1 = new Sql.Raw(`(${joinedAggregatedReq.toString()})`) const brack2 = new Sql.Raw(`(${functionsReq.toString()})`) const sqlReq = (new Sql.Select()) - .with(withJoinedReq, withRawReq) .select( + [brackLegacy, 'legacy'], [brack2, 'functions'], [brack1, 'tree'] ) + if (v2) { + sqlReq.with(withJoinedReq, withRawReq) + } else { + sqlReq.with(withJoinedReq, withRawReq, withLegacy) + } let start = Date.now() console.log(sqlReq.toString()) @@ -320,12 +350,29 @@ const selectMergeStacktracesV2 = async (req, res) => { const binData = Uint8Array.from(profiles.data) req.log.debug(`selectMergeStacktraces: profiles downloaded: ${binData.length / 1025}kB in ${Date.now() - start}ms`) require('./pprof-bin/pkg/pprof_bin').init_panic_hook() - start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 const _ctxIdx = ++ctxIdx + const [legacyLen, shift] = readULeb32(binData, 0) + let ofs = shift try { - pprofBin.merge_tree(_ctxIdx, binData) + let mergePprofLat = BigInt(0); + for (let i = 0; i < legacyLen; i++) { + const [profLen, shift] = readULeb32(binData, ofs) + ofs += shift + start = process.hrtime?.bigint ? process.hrtime.bigint() : BigInt(0) + pprofBin.merge_prof(_ctxIdx, + Uint8Array.from(profiles.data.slice(ofs, ofs + profLen)), + `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) + mergePprofLat += (process.hrtime?.bigint ? process.hrtime.bigint() : BigInt(0)) - start + ofs += profLen + } + start = process.hrtime?.bigint ? process.hrtime.bigint() : BigInt(0) + pprofBin.merge_tree(_ctxIdx, Uint8Array.from(profiles.data.slice(ofs))) + const mergeTreeLat = (process.hrtime?.bigint? process.hrtime.bigint() : BigInt(0)) - start + start = process.hrtime?.bigint ? process.hrtime.bigint() : BigInt(0) const resp = pprofBin.export_tree(_ctxIdx) - const exportTreeLat = (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start + const exportTreeLat = (process.hrtime?.bigint ? process.hrtime.bigint() : BigInt(0)) - start + req.log.debug(`merge_pprof: ${mergePprofLat / BigInt(1000000)}ms`) + req.log.debug(`merge_tree: ${mergeTreeLat / BigInt(1000000)}ms`) req.log.debug(`export_tree: ${exportTreeLat / BigInt(1000000)}ms`) return res.code(200).send(Buffer.from(resp)) } finally { From b6a68256fcdde6699756530deedd5ce686f8873e Mon Sep 17 00:00:00 2001 From: akvlad Date: Wed, 14 Feb 2024 21:47:23 +0200 Subject: [PATCH 07/12] fix: debug backwards compatibility --- pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 90471 -> 83340 bytes pyroscope/pprof-bin/src/lib.rs | 29 ---------------------- 2 files changed, 29 deletions(-) diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index 2de0f473c9c577d8a5175f828a9874098ac0fa5e..950568147d4a996b44f5f53286a4203c145d5f82 100644 GIT binary patch delta 22516 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 delta 28648 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 o;w4|7HG{zN$lw$+Tr Date: Thu, 15 Feb 2024 15:18:36 +0200 Subject: [PATCH 08/12] fix: group by --- pyroscope/pyroscope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index 621f3ea8..4f23d58e 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -432,7 +432,7 @@ const selectSeries = async (req, res) => { const labelsReq = (new Sql.Select()).with(withIdxReq).select( 'fingerprint', [new Sql.Raw(tagsReq), 'tags'], - [groupBy ? 'fingerprint' : new Sql.Raw('cityHash64(tags)'), 'new_fingerprint'] + [groupBy ? new Sql.Raw('cityHash64(tags)') : 'fingerprint', 'new_fingerprint'] ).distinct(true).from([`${DATABASE_NAME()}.profiles_series`, 'p']) .where(Sql.And( new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxReq)), From 1d255b188f7ff0141feaefbdfe3a2bcdf3bff770 Mon Sep 17 00:00:00 2001 From: akvlad Date: Thu, 15 Feb 2024 17:01:18 +0200 Subject: [PATCH 09/12] drop legacy code --- pyroscope/pyroscope.js | 76 ------------------------------------------ 1 file changed, 76 deletions(-) diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index 4f23d58e..a16fc4d9 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -169,82 +169,6 @@ const labelSelectorQuery = (query, labelSelector) => { const selectMergeStacktraces = async (req, res) => { return await selectMergeStacktracesV2(req, res) - const dist = clusterName ? '_dist' : '' - const typeRegex = parseTypeId(req.body.getProfileTypeid()) - const sel = req.body.getLabelSelector() - const fromTimeSec = req.body && req.body.getStart() - ? Math.floor(parseInt(req.body.getStart()) / 1000) - : Math.floor((Date.now() - 1000 * 60 * 60 * 48) / 1000) - const toTimeSec = req.body && req.body.getEnd() - ? Math.floor(parseInt(req.body.getEnd()) / 1000) - : Math.floor(Date.now() / 1000) - const idxSelect = (new Sql.Select()) - .select('fingerprint') - .from(`${DATABASE_NAME()}.profiles_series_gin`) - .where( - Sql.And( - Sql.Eq(new Sql.Raw(`has(sample_types_units, (${Sql.quoteVal(typeRegex.sampleType)},${Sql.quoteVal(typeRegex.sampleUnit)}))`), 1), - Sql.Eq('type_id', Sql.val(`${typeRegex.type}:${typeRegex.periodType}:${typeRegex.periodUnit}`)), - Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)), - Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)) - ) - ).groupBy('fingerprint') - labelSelectorQuery(idxSelect, sel) - const sqlReq = (new Sql.Select()) - .select('payload') - .from(`${DATABASE_NAME()}.profiles${dist}`) - .where( - Sql.And( - Sql.Gte('timestamp_ns', new Sql.Raw(Math.floor(fromTimeSec) + '000000000')), - Sql.Lte('timestamp_ns', new Sql.Raw(Math.floor(toTimeSec) + '000000000')), - new Sql.In('fingerprint', 'IN', idxSelect) - )) - if (process.env.ADVANCED_PROFILES_MERGE_LIMIT) { - sqlReq.orderBy(['timestamp_ns', 'desc']).limit(parseInt(process.env.ADVANCED_PROFILES_MERGE_LIMIT)) - } - let start = Date.now() - const profiles = await clickhouse.rawRequest(sqlReq.toString() + ' FORMAT RowBinary', - null, - DATABASE_NAME(), - { - responseType: 'arraybuffer' - }) - const binData = Uint8Array.from(profiles.data) - req.log.debug(`selectMergeStacktraces: profiles downloaded: ${binData.length / 1025}kB in ${Date.now() - start}ms`) - start = Date.now() - require('./pprof-bin/pkg/pprof_bin').init_panic_hook() - const promises = [] - const _ctxIdx = ++ctxIdx - let mergeTreeLat = BigInt(0) - let exportTreeLat = BigInt(0) - for (let i = 0; i < binData.length;) { - const [size, shift] = readULeb32(binData, i) - const uarray = Uint8Array.from(profiles.data.slice(i + shift, i + size + shift)) - i += size + shift - promises.push(new Promise((resolve, reject) => setTimeout(() => { - try { - const start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 - pprofBin.merge_tree(_ctxIdx, uarray, `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) - mergeTreeLat += (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start - resolve() - } catch (e) { - reject(e) - } - }, 0))) - } - let sResp = null - try { - await Promise.all(promises) - const start = process.hrtime?.bigint ? process.hrtime.bigint() : 0 - sResp = pprofBin.export_tree(_ctxIdx, `${typeRegex.sampleType}:${typeRegex.sampleUnit}`) - exportTreeLat += (process.hrtime?.bigint ? process.hrtime.bigint() : 0) - start - } finally { - req.log.debug(`selectMergeStacktraces: profiles processed: ${promises.length} in ${Date.now() - start}ms`) - req.log.debug(`selectMergeStacktraces: mergeTree: ${mergeTreeLat / BigInt(1000000)}ms`) - req.log.debug(`selectMergeStacktraces: export_tree: ${exportTreeLat / BigInt(1000000)}ms`) - try { pprofBin.drop_tree(_ctxIdx) } catch (e) { req.log.error(e) } - } - return res.code(200).send(Buffer.from(sResp)) } const selectMergeStacktracesV2 = async (req, res) => { From 20970314feb83cd9dab26fe129dd6038dffb9780 Mon Sep 17 00:00:00 2001 From: akvlad Date: Thu, 15 Feb 2024 18:00:28 +0200 Subject: [PATCH 10/12] fix: panic proof --- pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 83340 -> 84464 bytes pyroscope/pprof-bin/src/lib.rs | 92 ++++++++++++++-------- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index 950568147d4a996b44f5f53286a4203c145d5f82..21e663e5401fd14f0dac67f9019559ac9aa1fa41 100644 GIT binary patch delta 33028 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 Zb>+wkh%uiyGRBU|BXpLoxE zQd5=n+3mo!-s!%7RudH9zK2$Fc#i5R71c!F*J?)bZx#o)Sh7FU#_e$-Evc?Tp*mVC# z4oX~fB7JZH(J@p{tV)a&s;7yOa_T_vM_V%CygRRgJil~jXEn`apqanA^F!vzy|s7! zFW24iXjpsCRfQp<@@o+6K~7v^iq`Fs4sy`Ur|uc&KK$6;o%j62oN@?Q2l^#-R2P^5 zRDyMr)CJBWRMT#FAD)Y2ftl|(!A|n{6@Kf!sVBYpm;|rp*g<_3Z{q6BDYMr+4ipuKB+H_MEeMmVtPY(#?jRA=}%o3g}y zylJvcck_Glr+#_*(7MG;Mo0jyR?xvI_ZgwvwdgLWFgUt?c+sbS1642nOcAPH`I(0+ z@!ridO>=m~=AMZ;Y0DAp&iBxZk=>b#?9T9w>r}e*dI@Lz^x4FNB%a%1?; zgQK(WJrn^VO}cdp26(t|%b8<F*QV)NT6(1KI`4U3qy71l44rG$*;kBRJE8ge|=Z=2Z zQY$V(>u7>3eWXUV6kZ?B>(bl>BX)OV33l&_7E=>^+X??NoMLVa-wc;U(k4|UZ7$w= z3KDS3*0bGT?+V}8I^O-&uJFj#vpT0l)Ix7L0JdqTddm=-5?=n$WIDV1p&3KGoU)qi z+YfcrOR`H{J{kV>p_#b@2z)hj14QVA&u=Jgx`*|#EBUKc?zmFT9TT0vA1t<^WZJY{ zlS;V3Zv*Fr@d`4934R-UhO}~nHgvyosSMb>dkw8;3>I5x-Qtg**_IAld@g&T+eK%p=xAXZzj3qNm+7uHd2-x0?a) zeD7?@7Prs$dfe@jNEGZe+9eeV%G+UzJ_8n061a{xj=8(u)MB%oqs_r8mG|Z8%m&ff^I@tn)$L;=IwR>yHuZ_1E@uPY*tUxq ze7b+^y?$|hp$O$U=jGY%&vfdG-Tm%IK}6A?*gx;y^?rB%8TYP_R;*T~PZo+nLk`Q^ zJWY)AifpiZ6I{vOnxD@>C(KzwYkh#JQ;+s@Hxr@A^f%k60}4(tS*`ZH%2K z!%uty!WA3~X|Ui87PH|EyT*U+OPTPSU(S{qjmtqyZC$3mA)CuLA`cDnBptlzcx^c^ z>o*3kV7<7s?1KwHA7nV6T2A23cN*M2fc(B$6S&&t!oD$iIU(rwTKeW%xn%~^kjd9hrSudQM=aE85&RfLX} z+Tv=b;z+^YCeh~vi5v%YbKKd?A2|W}`8F1=f5b0ctpQo!Aj>lg@{K+~5MO1jE*H}4 zf`3$y^)3?T8{yr7LMo=|I$G5UC>LQ{1C$Go21=b}56!I(Sip#iC7i`9>iSD~7`>{z zOa$z9`fXQ-*(hkBgUmpofzpGpQikG;v}xM&A~D3c9DU5llRqUjuUM4ThQLY}ou@Aq zb|8_#LI(`jQ7JL!LoX|>Z1Fo5=4*qawRO^e)US&P9rY|cRLC(!c0!FE5jCbojmTP2 zW1{3SA7Pb=;q*s4N+33M3l$8zPv}qN1bWlKKZ@wm*=YTy+p)rxQx>xZ7p8j_i!cEm zs0Jz%KqL^AiAaqOB2qi0=)es|G*pq zgug6}D%Akmngp&gIvmONnklJF6;R!$;Y6qrpcd;nOG@_v*%~WzgQ&S?l2$Y417|Yg zL`rrh6h%Z{L6+;+FTvKq{3(bH>K9^yRN)Ir!c<2v(<4JklEsKmtl?)Wd;%)OCniV? zKjQ|uu;$?tVGCenBDTQFa{avYOxn)}>`CwbH2hE-d`baq;pZ7z!i~AZH2|+yr;#RV zlc7zf(q^mL)I@DE5`gS|2O_-&T}QwNy`>Mye3|d`yU^~Ckg1_^vDL!ant;X5B#x#X z8^>)Bkx>)KY>L>(1_}STB=!t^E!Vu&2@JA`({3!ItiLb_quQ;wxr7dHPgRy=p z#)ADK!fX&~(o7k2=I~szWBD_Sli)E0DWn{jgbZuI8mP4OQzO-XJgE;BRo$yphdz(( zepgam@|NmWH`v~BpbxKJ!fI9hjCWC1ZkHj;zy1R(e?$!P2G+BQF(Vgp?>7>-Zh%0a zO_2EM+@J<4PY8h#=D70|lK}|rqvi-^43xa_hzpp&Znci>Dsk@FuFkPtp(^9PSlS$S zk?lS1F6m9viZ&cgF>ApkHNm_AzZFR#F;pX}?3_|cQauCy*rdpclesBhwxA>%fh1c* z5fQ1QBS!hgs%)%jOCRB zi!d;RzTWsOhf_PzR84Gx_{6AzO7Jc55d?oFipeM^_>YRJ`Ac%s`!yw2J47@!$u51Q!>FTrOo?+`V69Ww&?ztRfuU> z_+m6q*$Bxrg~buNN;t*#bdIbD8I|G`MI%m8=STOp1iWS9Rkz2iV*NhYLA?Xk7z(=O zo7BEJgOx}y#0zP}ds_BVjh`ww;RU~HZ_LEBZ=FLX-0;JWv$|Ju)|(05eCLI+i@7yZ zsE5w&M$WC!xf?*!9S|!jbEW7UvQ6mRm3*w1)$r?1lL`OnSCgA+EK!3{zzB(l%b%WH z8t&6$VVbh6PC}Wv-7B@A-hpI6w!A`M*85XO3kaPc=V5~qwnfQ~IO$8>lHKj)g@-y= zFCxfN9kd;tF4l=6XHXUy#l6I!$Q<^oY)c_tvA-2^ut6gz%f>&NUU(@TlN{kCU` zjw&V2E@cEIj+9(H_E;JIJ7ge{) z+g7g|srnC9T^lBAcGMxv5=)|Xcy;c&)CGrBA6>6)v}TXii!Bd0_}JOJl~iYktLmuC zv^PI8Y(}VlSk?3NZcWs>U}mK{cP~oEcK`n;^{ru37o1qB?~XK^Pk)B)J-UZ0G@DtK z>N@W~22)>D^=8>M@P97nCoav%6E}iObJ16ZT$%>w<)RlRrLIP--T1=jic?eh`@b@! zn|zt=k&Th52u=wHSsDEDIN{mtBd|8_?ws3jlvI>OfIyQ_ThdizLu4(2hG5=GE=Dv2 z;j24ZtU-_u-`G8CT%LNVNX1K_NyTeH1-54h#onhUXYjR1<7L8+K0R$DIf%(%<)BOl zCOyx}!FdCkBZ3{HjPfcu2zaX%Et)ctYgW^qN?9b=<`Emxw0%~+{t9cU zRSR5(q*{#}W|36G1#qk<;9ctw0N40=8-uqIY8ix-yjyll5qSdGt{&qFD7k3kXoDif zk;HtwXI59B2@}5nqQyQZUb~^3hht2LC20=sG1}T&(s5v?B%EN0Nf=|A(bu z%I;)J!+il2DToVY_*TY+lq3~Xl8QA}Dq4Yv`!{kESSjQt0h8nb-UGI3oCr!C9CXUMXXX*tVJ8xQtT$H zK^8{HweEtBsMRt1R2tK#O6BfJfqQ#+Qtj@6*`(=GiKaVN(N*tOOX=e8->xS8i;1P_ z5RD^gy3~l8uJsS@R!c)TW~TveTZLQKa3=(L(VA>it%Sx!6=}M7W5~ff*bBZdkf(zm zDv;Mf8w-Ko@jD{qHb?_VZCYZmTidwJOP}dg+o;iyh5SK#$?%UpMVe#*`dN6MpQ z&1tJWs$F56XhwWst?#)0TM64(`Bm)-LyR6<{cTm3d2FRuwJWU3z$`&~arYJT*jkuU zAOrb9=A zb~^yN=^^UfitU^oB#jr+=!k<(bptAp8#mapg$~gi+FY^nv03&PDXR-yoCbmeyAry1#b8z?Zn~!BsW$KYR z?-wRU$SxG^KzD@AM_SqQ55I(ogy%?1Z@yBC?G4X~{SIf`^;rTPW>*&#IgcJO8_5Qo z2YMYR_z$JC^R>C54BbHkGWEeB95AJNmRBF-aUSQ~8n(q?Djh6a6KpRn%-fTkbnplr zxY{x2g9!uHIg`UvLh6n+!K$;c9@0VIqI^ms%*I?{C>}i;EFSQ%wc#Ddk*Sy01;F>0 z>CkwI+MTyH>Ef^xjWPpBtE+VIATtowS-qgnBL)i+Tm;pNbd^b!l!e{-9Bohr6O(`d z%#||oY>lEhD?&N+0ro5jN4{&ZhkX)8@9-rTVoK1QJ$uB|2o97X?&&(KM?#8kweTpW zgE4VIMB@%3zo-NCd7?a7hy0)7&d>#x5oGGehRf94N>QfH-Y?aOh$z*vrh3BD2fMIP z#urCu-4aGzPtkPj@w#={k8r&H91D$Q>Gl3GR!v>-83|A8dZG~V zX~mjVW*Mr}UGAu}_p+)>S3=9GKBW8Vj;UV4mGqUQzV2pFAMF$C%GzVa8*zvO@+vH4|FQ8$<$EP=W(ae7cqs+nhC9jr*Hm&C%{mBEOc$$W z6OPp;NVj_uGguQFsk_&(eJj0PZu@v$o|~w<9%7f$ZuU{#Mf8_T%<6(JKgzsbj58*Fq3Jo0+njjk=*@_q6c5=~Oi(2h}7eym^b5qNr7}wM;Wf<_#1)v_cBk4GV#`aB}jN*sfUSM6fxE=7>V=cIk|p z(+LnD;SILpEKo_F$E5w*l6Yaa9zPTAP{;}9W`*wo>pAWwqVid8B}DtMgIEb2?~GC= zN^MsPtQ!8ljJH|_$va&nOd^(GreWvg{j`E6-M)&{94Z%Whq}ZwQ%u3>y3CsQn+6Mr-a78BXBRN^ zTaGjXl&6zYussF{6vp_C{^-D5I#3)fRhX5q&MwH;aK8~O73vt&MREhF1%QqD%~m1c zM;-`#Sx*;s$nPn#OBpOQD&C9gENHRUk@2{o4(ghL5UBG` zlx1qM25T%4B91rZjQULs+zl% z8cc$K&PHJq!HY$)3Ep>Wj#!133pU-oKYIKJxdz+f1nvReQEZG$B#_^W6Tw@G{Hc?b zL!G;+!j8j~Ys4W+2=Sa)!Zgibw9p99?Pbr~TyQK1r6IC#&91h^l-LZN#X?cq9|)}% zFF>3|_XQ~6{?!on7e(05tJ*omx_=Ay{Xc;H#&G$)t)-Fho%bg_5u|SMVXV3}#U{`_ z2pL>x<(DX+sfq%)H4#&>t2si&4N$T30aR?)(L1z`{?L83Z@i%1~u`D1j~qELiA{pKmDz7JEUS&E|%n=6`4 z$va;AyBe`NQlS6mKR)zd9{Bd}e);9n9bE05zUiKkGKb|Ay0xK97dXHK76n|F1w>lG zL^=cFb^PqYJlrLzi0JU^bcGx(gI^3q(=7_oV@z1DvH)xcfoM|oIwq@s^_6B5?`Ls% zR1J%fDMd%$Kwz@&_BdK87Pa54d%un}r6kuR*(W%Ym@4z(Ev4Nn*pc%Bowc3CW(cTy zJK3OP5YnrYNE?FcdUZobbaTEAk|n;(fNtKCt*S-Uz}(UBxA|$bfR4J5aly_i*-;8! zNyLhT$6HB4M!OgEW{Y~m zoa$k>QG2B=itLZL_H8!nNU5qi?w=vEjaFMCYiVm@I=X#+fj38oUfwUmA<#YUx;4m1 zZx1$-@9P~BH00}UtKJ(}QO_%F8G71&W8jHnqyS{=MNbS$^PP0?`u+Qz;CS*jK0stY zzx1FkIH-sPyKTBtO^51kRoz2zU8dGz1-#g>1ryP}JA*#RO$Yn#qoYrNzVVb!5CGbc zempYyLOQ(aucwz@`mAgkDRG9#5$v-WnaI^-w08}nIvjFST!%%Y!o!?sSwC5@$G)=3 zF`yK)Om8R7YqNQJmm%@GZKp=kHWPbF*U@x@8hU@zbfWU1TwR+Ak~p~RPidRWZN@q7 z(J?f?~@uK<)_=gZ;Y z?{#J0epDj^86Me;I@sO0^()b!WC%;yHLfYScLaN04KF&lps@ed{V+L<8@!-cO0hk} z@Z!SEWQN~3SQvVuV<#2zL}y0zEWT0W*3&0b!6V6Oc5wKm{fIi!bS@Y@f<3mXSpKSSzF9Pa$M&R zHd9DFxhY<=P393}tFz%w!7KdQ4@O^kC0`x#@ovjDGM2qWK#(+fX;7Hp3b%j!x)7m{ zBS*eU$Tp&{9dL{?pj0xNaF}rtnGyEFmwvFQ?Y(fn6MRRo!o9VBD~at7h5l=|n)||S zuPqsO=n=K%U@Caa#ym^!!E@U+$rk6kyLVFxcHjXyiUx0wV)g9VJeX8)uBy35+Lj zXeOZoy<@!R{0Xu&+SxY@7V_bvcZ}}f2EJ2hf_+R%+o^VI%(K%An=hUkuD_cr_~a&* zdX_F^sk^tcGjV09yLU546G{ZT(i(2L0YAHDu-M5ED>bs+f#AK3GO*}o4;Dvjo_4XU zp=t@9_Jq+(C{J6J;;4SddT~5FF~v6P$MHRD=IqDI1GJO{r0j;VGs1$dW;99NT8e65 zYHW$JksSf8k(((t#;;ac4bt8OPyX=9A394!Y3w5akKBndDVBJo+aA$k&dLoOB%(c< zL3;qhzL`$@?a^gdF5l-0ImRIZpwTS&J8~-v&A#s9v=_3>+P*r|eNexF-H3Jn<-r(0 z5qWb_e@cqe2(}nOZm>{l)}*j=a6u9@_&m_&;gB_mJAKZkGhFVqGwSr))jn_40x;0X!iAQS znz&%0bUU!Nv@{BJY1cOr6{Vq~ESM-}vD-$bqN8ZYSQ_eBDdUsvqP)2HS!OT~krMgB zupD7_N|GPe4Z;|f-hn|O$NG4jh8$R5xWUCR!det5CoTyzI8s{FgW@TS7IX5Luc6x! zt*~63>}I)T$p}JY7D-l|8Em^JhDR1NNP`zGJn+i(aLCgwVD!RRqqG$>e)lkT>L?k% zOJL~2`LZT*?+#<8-XLKm4EQ2o$Z5G1F!W1ucC(ro1}26<4j8b+l?4t;hG1Ycix>tH zxIHCNQoCT#Zh_jMZKcj+L^=(X9mK^@+hH>haa=?29#QQZ#C57h@D>Cq_#Glt`gIW~ zrX9auXTR|w!b8|%030CM&i#fd?!~Y(H6bybJc`n^10M~Me#~adV@)oy-frmWa|-pv z43?IjClY2c!gnXmndn-r&M4QCzw(S%FhHj#7+o z<1N&AMo*zfL2nUapwxn2D1Ob9pkq8mv;E`b**PgNR_-^b@Ny6-B=hFfy%<(*4l)HE zyfP(`l)G-AFbCqRL5OuiRh{%(oTk1Yp2AqwhcVG|of>(onw7aeO!^3wJXCgPnE@+iJ)n$UGq;^tw)2}7$CO>t% zRXokAQtS$sA8I=lAF@0Lerjnk+r_v(zfqmpu0k_|SRVG9yTlhY>se9JpQ))9qba>} z&!`67k77p6es_5G-De|%$7&X1Ez>r~8nD(M(tvg$^ap zbRi6^T8bGKEg-6n)bm(o#jThEG8y}5ELDnmDJ`(d9-~*f4DF-(Xbt)2SiKO?gf9&L z9Pu=)rum!joqI-m@|_g~SLqu>xm|@$4k8Jh8xlQrRja6FM_*@`07>WgM$(Y;CD8Fx z;AEw?(NBERq2SW}D1J_etQ{Y{>q{btBbjuuO{U98b0|u! z!~6(VFC^te zGAyf!79qJHX(dy~`x@{_zV9<$W}>A>J{q8*t-IUO$rO=7v_htfwk+lciWAuYuv1_S z{uCgSTGumJm`Y(jhFM{rl}@dY!BnBWu%_4nR&#zwICe?Lm}uhFh~}FMek+I$&s);b zg`9{e2V9a_h0EL!E;|MRNXOt!)PV0~8MDx03lpQO!qHf6T|-%dWtc~=z+`Aal!cby zwiuAvfno>E3kAqmWN1^Oln%cT5sV~2-YI2~G(1nHBV}X04>E~pgg8%~$AmO520a8g zF`C!0t#l9E(QOA^ACL?jgv;}OYqT|K^I=KoEE7Fp%U(sHFWs9afa{?Z>;-oDl1rS_ zsCi=~qng)BkhCnJ+5*EQa102NF|r`DrZqe#bo-qP3&01Lw~kfRIOm@L^ou9h8qi+BXg`?u zM~O=jNA~_q-iqy^VZsNN)Rl^(>|T=>EvoHjo(SG|pa{Wzl;Ga9hDi&vHmgmm&OqWA z=h}DJG%5T-VxLh$xLWDE7ur`P;)9Fg$ja(iY3 zI)a9EkxIdf4e(JZa1c|nI#8P|X{1JmHy(Ek?EB>w`vkh!7H?EsVW)05c6bQgGXchL z(#?SwOYR*hL9;2wQ$~B>6@L_J+CC69s4d=l4*1lFP=g86bTn$3(9d@+X{*A9Do7I_ zjg7W7Os#?q5PB3gY&yXP9moKZB#iI@H9@zz{^(uq?FGJnQrW(znNaG9poHlHm9?$0 zEoH7H){EttqV`e+tgkG_2gk6oZd>Ht$`Hui1zLng8F;T5uta!3A2W<_scpI4iZ_9z z18`!Fe4Hj(*#UurNI=Mf;>IP>vsjt>OrJ+Eqd;$?KMLhfXdl5e>VY8H)-&QRR;mqN zvKP=0rZ^`>emI5XrW7N&_E{{_8Oy>xi(SV%YdpD_~LvM1)x?=2n_{iI%R>&O?I|eLpn3wzo5sb9i0Z7>R*1Yz| zstdLmf}iE8*NmPUcNA(B_=P%u7N-`I{n?Q<+7(-@#v0KX*d{Xej*E?Gk*_tPPZ%=% zCd=?U%80gB@JWe!$L^aPUU6u2={OA1*n&3Jg66m6Ko=LHvfyP8+h9^B!9f`KmCfOM zpk2gpSRtQ(w7WzY_>j_&%-VJlO88T7aa$4sD;7#N zLzX43z7Nw40>L^iDdZFrtCRC~u8Q+XnrV1bL;=%4hb-a9%J1~&NaEXiY;350xwZoh zAf{l1GmE!os36Fc3erNrKnDcYGt`XCk}Mta4B;3;h0CGL;X0}xC`)N@>Bh2uIMfz>_18 zK@UomGzfPj#Fx1%%YHkX@56?l{q0mUFWmRrF{j1uO~(oX z2X^NKgTn`0>vv&UTwqLT=tRMO)zieDUwtbxZ2q6KO5bdC+e`KFK}+)420Pph`i4QK z*b1ceF@s`T@*#&DsthAqA2zcJ!Xp3;x>(0Ev33F+wN$Z!CDL*Y(u-s#9)IypPWqcm?6zp63 z)G!I1ijMs9k%X3Q(8joYACprb%|aK8{5ts)Z`F&k~6J@ zh2CtpKWdxwiyuJ3gN;%I7aomSPaZI_*Z%3aSG{)^Ei5z%-RFs>Fth|ftR+a_Gv}%$ zu;gf{bct4f{3`s)?ET@BX0^x66>Y1_MJy&KNvL;&)UwA^QjsYnKnckVA|l07uRq(uegaW)~Wj$NC*guv#ol82fYqCcF2^4(-a?zb~{fIFCtZaqEJ^&p%@ryDPR91 zuy?-rcsU+tQl+H=50P_#zwVIHLbM5lG!-a1lCNqn^Ax-<)d*(}iF!-oI%H8D_2z1w zOb(wgox(v}2=nAQ@Gx-n$x3)5*nA&i^-Jb@t&HTuQIb?GoVZ&l`>9-2wW){EVes8C z3>@<(8&e1X4%0nK2|_MSGEMj}a?sYM!gs#dDR)^c0EYM*{^xxn@D*8WtDlNkKZR&0 z@X(PGc3pZ1aa73|Tf!HhDABtrD=uuCPFsR=h7y5rsHD`zVHF;5dyB~NJ8^f4y{AgPJ1{ry|M21_BdigUAulXdy5^>QX3hjV2*&90Ps$&wy-v#KHZCVL zww<-oGx`u6xJM#^=V&ngilgsE*qUzTct!UB}%_WCGhK z-}(wsr1jP_jibGCs}6s){L*~FcR)IZ=c2Hbj=zP##0hZQ} zP~VW4+YHRMy8|l*8qU#Ua;=HnvB3dJI+?xtgifniH~L&uwjbL~_Rm9inBzxF@gh*s zq{!yL$)2yjUA61whxVJ!i9?^Dwl_e8BTO^x!;sYuvT*lf4;?Xm=9%(o#?0W8;blIr zUYx|8p&RIh*}@IVfk&>^ww^ESU4|_PnlE4?f7b9U(23}?owf2?`Wz3xwUl|NEr zCc8i1RlcLfoYeZuUHkQIIvnBHLs%HWuXdHcLxrU$g0u*t_-G8@FI26md^BPFa^ z3ail+bZ2{Lf@R1pCkO4W9S7#G3HGr$Vfgx5PG3g2tXDp*)|^?ou+rAP(G=cg&czBG z5XYZcwLK%MbTlxof&VgEPuMr%$_yQ0z}*j zSMoQlU}&)uxiZ5>F%KqFMMaQM`ETpYfuTP%A%(R0)$-FBvztF1SH7&?Y>57}9Oq;X zf7+z{Kk7}NyXn>Plm>HJ=Q98r7Xuz^uma4$pPyRX`5Y;w|v>Lzg{j_PiB zcBt-uYBY0BNy;@w5?4F>E$14jS`RB0jUE>hbggjP>91`rA*u_|tul6lKCV{ck+D$5bN^*m`6r&4#-A`KH#D0o+79AD5KB7_<^Zu7 z{0W2d`exJV9^76oH=A?Z-|Z^@tl8Y-?tZMivc+6F?5pJmcWZrmb2Fv<_bo`48=dkU zt)_QawZp@znH$S%TFuGBYVCOX=+4AxjZW~-;6FGX+Pbd%FLZtC;ipK~cy)Fg8T>}6 zG~mfvng2FVq>)EW**c&lq1Z?=*vb7sn!q4ewwa0UYun2k+stR(_jZ*>x0|W%cONf* zsNEblZwIoLZaSwk?o{s`aJNm1s&`^_4!BJ(GhtKseYpeNLHc5k_U0y6RKFPCReFz30?JyG5`!Au`x2~(fhh)C4F=I1;mc=(C( zUr#V&-ETYPUr^88|3sN9BKIlW;hT#ue_9ZGo?qTFUmtVyc%tG#BHExqC)Ow)%SYp# zpjVy(ve>PlLHKCAA5oHQE@jOgpbKOB3cg`GEMHtO#Y=FDQ3?^G%RKxT+IYFV`qyEs z>uE0+91<8nbFlHx_B+8`a{Pf{pW@rpkzID$)W&KD)e$`Ta``~P%x`-Vev)kLinl&diu)iuR3AvP4k^2DbLZrTa4!z!j*&#gdgUot1A7G zVd>SRXIGUgJ*g^vBk{gr>6uZwWCu`%)He^kHxhFt97f_Enm56`tqbK zLuL>8NjgiqdJ1{cQyr&NsnA3Q$HbL%^RNzDqXw1oDZ}b_lKxOt`|+e_RHeH{NT192 zl@7-atDy9`RUQ0}cr}v#7wKx48S0->RX-rzUX{LJSbCMxxvC25%1e99bmNsbD475J zo*wgz>8PcK4uAA7Q|p0*%^>0aRQbQnz+RkPTdtpJ?#=uKC7skPPn%?VOLfFD{G{Wb z>UceQBI+bBOMHk4AmqA;B<3=`B4tVXWYSZr(x;L>zAC+VsD7UvV9Brsmkw31Rfg6wb!m#>)*WUniXrWUAg+! z^83B!jB?`%rt@r`5;&9jIguZZ#GEDkT*S}P)z{y&dewrpYgezmdiknVtJnE!S6qGb z+MBMwWyQ)*_{*P|oWRd$YUrP8cJLz-)Vw7vBa(gp{Y}&hwtoREZ*4E%bOPJB?YZ)!Cz#XS*K*~5 zIKf<)Z_9hmIkb?JIkBASH4ly}lXVTr0zHdjll0j&OuGC)w^>xawb!(j%hSy9%f~i) z&N3=J$d4+EoUgua&TNFbvxhRRhjtd4Nm?RRb(6GYnV>V4A2Fp^XB6Ux`jGP4@K>v>k@yy2A}on^+m zN4)a4XYoyd?&fmMY*Q>PYX*N*zmFfSK1tu}Mk}rEdOGD2pb5Q5V^yb5Bt45CX+Do1 zt?nd#=I}F@AN>=k=JB&=`AygP>z0=vpKaRRcbm&E&Ne5y9WCW|W}8v%CsQF=AC`a> zqNkR}p2T{#w0IV4>srcxa+2wvdK$(0r+!c82hF{9`PxsQcKCbm(}nkIZ&)XEw3c5! z$(%T5QLE>$G-t-l6KBmnY0lhvCojM1>T6b9+uK@ho@3^m)JwVktt3>RNofDF{NRdf z{N?NX`AEwJwpKLm!t(k#W^Ti4H1WxPx3&D@9Mj)2vCXq!m_;bIIJ>RfJl7N#C;2Pm z^7VuQ{n>FipH7l#>?BXqJ&T_NB8!MG=I8A4`nl#T_g~w}FV8hUZBY|(*-7*zj$=jN zmyekY`OC=Hnok&2o^-OA>TMt`De!s1JYjkH z$>xp*bXoA*ufejj%I}4>;4ODIyFNhmrxnNSLidI#s5@hwTc>&VwE-WdJ)Q%up_)=}<01tI$q+2RT< zP-OK|$MY*sF<-A~*)-m>*2PjXd-&NjzC0r^C$t+kYw13n?oPV1o~k6!fh?VcBqRuZTEiX*Q5h6u6A-#XHo~F; z6;`7JiJo8ujTj}8z$6+>l*|>bJ(}TWX1E#^N9HG9qw>4r3^U@$Tr&<=e(%q7PE}W$ z#_P=QkDI)@pY8kX-~D->)2~M9&G)CbOwM?fO2xUtJUPAJw57Z~<_VL|c*Zft%cZ>N zR&zqdbDBKQ7}M0`rrfNX_FTuyx~`jco8444<+_=aQy}eno|8&@#x-8b$vK`|a8r55 zNqMQ1<2Y_Al`>x5a~$Jj9ZJdKA2H7XJ`EsHWCGxs=9F7VrP5}td53vNG~Hcz@dxtP z+`4wn`VE(FSbxnm&U>1#UcY8-9Dl;JUcdVK4VSOIa`p8excs^`YX+S?rtR{}Z@KFF z)mMM;n$?%zaOJ91Yd+vyKc*pX{WWpsx@f;!s(i+@Hk4hf9_}*DYmF0{{M$E~COj0kUUJ<^cp&L19U6eVn>Uobbs7PKyCZX2L7+j?Le~kOel~hGb4y>X z(WYfZ6EqFC>eO2`BU){;tv1zKy*+zL+-fRm^`-0*%_?ZV!KIG}o4+2#oF*5(oIDgu;5sVI`hUN}fJcX@EPTqC-iM!aCdwN<5d8D6E4W zRpR-iL}4B5WhGurN)*tDy>e zloTnf!@a7+OG$~sI@mEKUP($6*1|sqN^DO`6xPA^DX}vtQ5b{GpjT04V8Ye`cud&|vx8;VZe3#y z$b44oO!xU`qf1)nO%;7wB8AM$)D8GKX9AUodIP1Dh1kw)S?vxdY3QXmf#Y z+q}v@$x}2} zC~mjpxP1Y2S-P-wIUG#+q1{tBZEO391+mS*t}DIwxA&cpv=TE@Cs}<{Uw!o{=DNFm z*1MlqeB;KA>b>CQ;|+_6D2B3)1nB`gK1OOnvwoqQDww<-NRSMKRx}LOAxK9^(RwBzo#SiTXGZS9x^(H)&1H5ct~8v83_E{a|q z_vze40a!K=6#a{$EnUZ&FDiK&GpSE@FB^MNDNC_GP#zPs`4^R%0~_vtrTcLMWGe83 zG5$sSADM92G;P{C;J7$*&n#0OjMZ>HL$S?oB`~P?F zWZpgajcDJ@HC+cDr`ku2lUJ{ShipA$bD~AFP%WYr4~)wn{iF!83tY)XZ_Ju!uG&9u z_N6AfkL<9;AB;Xd=X!I)S9{kR_wYBO4Rcp0cy{jO3D124&4cv~J8v#E1*sx9z$SoG zhrSWLG51{exu>J^=FRe7{x6JR83Ra%KT3zk{!6rJ-j=pQU!n1t;r4w5hfH|%$!Ny> zS#4kZ8p)pUUle@a4L^A>`r!Pxzi;zS`kCc8OPm%aV8YbRVe7hZIJanXvm)vg(kldtvF?FbkBmR|2GG)xMMft^0#UO zO_&Sg)c))msXh-jK-VP`kdrMtMJHd^ zVLDzjXSvNfS%%TN+pw~Yje-UKk6h>9%<)BHOF!}u))$DBnYv@sAl6pzptyyYNW z!tKiLGGQR>u&++rsc^vt(xFKQVH!C3OKUSf(WPA>XS0>q>8fMFx^}g{rG~@ z^V>f=oI7pBh3+d4N4Kmv+w6{pR!m)Z6>S#sLDMdY*$awI`S6v8>8!(cmdl5KrLMbd zsyRR0Tla;NOk1?*!g96-5M6m;sqF@~))SBanyUG*rRc)TI$wDrW(}b`*y1_HEzrrH zsA=U?m*C`;Jqq5la+`u*uM8Bly~}3)dgbK(?|s)_X8stlEVyLZn}}u8B_oOD&?ToQ zf;dKosO3^Ch)=k5VVh7hmPa)Scf+OQ=N(6EOvVbVI)1a?7E5eyf+f)nmv%=>JDT_Z z_|mr-^YN(rvRC>2gZ{?(J)4&4hOI?h5zOfxkQ9*)kqy43d9M}JXF2+dQ zas5^mKR&RAAnIOqEx$LeS}}9C84vyV;ZesYnh)~ftIohQCn)$=3fDHeBv@$%-H#GK!Y{wy$@{A@+zf>BX!PFI zKbDcXaLuqGy>89i%mJ`KhVSERK9Pxb5#O>aI(_Y8_vmBMt!rnw5ABL}t)1b%_E_}& zwbv>0v~^S5ZM&lPulrHQ0mP(V74y&1wM{(~oxOgrX{QRd?f;AQHyQJ2G-tz9v%0!u zytyoTazi&u@V6V*xJP$Ir`;4Nxa_8j6&$?j1O-QLn(n^zXq376G50&WqOaUMpkTr+ z(>sqawph}jfSE8(M(?@h!qWC{LuRFvJM2M_UGLV6`h(Bz|8KYa-bm&6_J@x7k7~Tq zYo|#c@K;BF`{9es<@?JY!3}gQicY+3S-cE;cSSeeR-U-+5zEZm9IHK~WD=vO^tc`2 zmv==^-gc5!<|nsZ(K!rP1Qn5Nz2UZ9`&ZunkZax_y;B?bR9FB_9=Ugt`}~gm&)oZCli9|~hTFa!eg31}6J7#O zATz{`Vxd{$IN?#njy@ax;G-v1wtqp~)<=bVktJK`7Q#)`mK=0L=WMDe2_2dNq=!v} zTVjAzCBWYkm>$?Uf~6^Fn&Dw>6l&!(Sr`bn#=xvRK()4!2_yhO&G_leW8HSrWZ_=)$l9{D&6-yHtEf+l}u^xIENujTzzc`5Qvd~kBME{>Kz zIJGV%J*4DE9+Z^)!h_v)DXCn4{|s_}{ovTC%@XmcaN0n>Ywf-e7tcg84n7c1FBLXN zJzLPmqf55DV?3*uMnI$ExDD$DbNX2H7h66yiDH*x))^&e{78t)Ke_Rw*F+5H5Yn-X zU4Ly(3atrx+q#9q6T=;7{Qd`{=1&b|Yv9pGKDA$%-5V_$_xuixEG0zJ*xfLI!t=LB zcSMW3PgPDj#O9kw@X}-P9Ma*E=zGx&vnKlY=!%#xcny4EaO+Zd)vm4Qmj8Sg18{|) zT|I80&7fW`ap(zci@c8TiCt0qLuYlD)e9m8+$R|Nl6uJ!D@QjzbOOD6=AqtU0`;tv z`sDYzn#G|d1|N<7?V-7adv?av+z>9f@Y5Tw+lIK3f%4Q1Zu*Xim8nh`43@hP7F{yj zguAN(4XadEkS$FOK)xWQ+^_>PRJj1Nn*K&Z?W5jcIZt&o#f9zyM9&Lmz`wvhH~QH- z+bj7V_XY6+vX2^BHKpkRc`ussGW}uJW z7`ZK9L6$#I>d=xogXK0x-9}ax_Em8EtPa}7vX{Yt1W%ok6aCG$1#{ZMzQLdkp5>nr z0Mf^D61)TUp3MhsGrY4)Y0G`~_P=57E~TSc56_4EuYCAgla3BQ{NYLyt7s=PxVL}e zeL?!R5nXca_1Kb0G8=H!;kP$yO%PebX+y z5n9KR!zTEH6_a|YakSRt6jX0S?yk!-gN*VGxV zi5ae`Gh8Ex1&rSy6c)OHjYY3~KB!!!4h=ZR^f)?c!Ak?07lJX8non!zGvT)tTUHeT%U zv^!o6=Hnno130*RN{>KJEflv%yrCW-_50%gK?{0Qk&+qS;xb6j+KRfIy%)1TEaa}i z(j;s@SWvCxf>foCbu^StI~47MIvsXbv(ZukqKVk#f6ibEyf*)GtojI20I z6AKY1Ie^irKwwbKi4lb(z1b29AREM@P&CsfknKEkDPtK%`HJ-WT$A}+b|%! z!^p5Db%c{7j>qq@10HSL#kZ=E_`Wy8%QmchZZA|DQ03 zN5UV!d!nD==8Z1><~*o}y08aPk3oM4+ND3Ff_52Uh(Hag=gos~wSLPCkCU|erSR1?_M3H2=~UI5xVB_}8b z6ON-P$I6UEDV6He%X(SHNW;g`R7GrfG@>evAS&A=M3r#(VnS5VNbP@65?z%qGuooYKb6cV}XcXoP$B(lK~ZX0mlTF#n3b(mq}}ue(I?vni7j+HY#Cz?CIi$l;J+;>GFUj&d5RR^ z4Nfr5lDH+;@J_n9HEz=zh-GRy1T7|zxSA7l zwE`T9J`)c0Zfmu`CXRFm72oIXASw$8abAfu=Ciza!Vub zle3}hYjlAR?rXxreWtytM0WVnZw^j8hkGogBIxExzM4Ajb5bPSuRwo*3;Dt68uH7G zf*6pWG4jJ}h5X{V1t!KC#<&l%q=s?duyrx+3oZ{JT1AXK0D=j_xQ_yrMOnFXW0e10 zd*x9B!n?wA6dz8Ea) zUrxmm85ecnA19HmPHNpm4qC2l*A=GPmXDLjWR5D3VZrAFe?-kq3H@W6YgQVuiYzWl z7Uza7FL1|7x>(g^CD~<|5K8N^B7`KqTflV$=h=Ec>zxTdtH4Dd%SdID!1V;Yc{K3P z3A_M!wi3g`YZG|<&Tnr1@fv(42Ddhx9ZhC5@UID6wvh~CMiZ#@oCeRa@$s#5MI{ps z2_6A%&1T>ctqFX3B)q^6*T7{^1CCgB{3U8WH5&L4ffs2V^cDErI=GnC@xxK`KdHe( zfr6h`hj&M7{vQPH(>w$y@cDIcA=jIB>h}U~Ls=2M7Yeg$LL&B`zm<>x53P`hUj1t4 zNUx)ZY>NK*tK&xc9m`f`c?tJ!NjP^=V??Xrm%lsu`#r&hErDC(%+QwQ%u-9>%zh(h zCT9Z{i!Ua6-UN8GZ#lCcE?!k4D~$en=NPM%v`6Reo$s{=#c1Q+Zv3>L*?U5^CFYtf z(c!(bV&2$rULZ~>-pB$HvSu`C2RNWHB3VY5_|~x;%lf*kj(MGx^{2sJVqUkH*s!ec zvjYBKoC=&S7WTib3H#R)VZXS>=@?2b#8(yzdstk&k&O<3=f&wV>^pwgj_?&2T?-sa zj;*>^R^;*1>nVeeLk9RRjTY!$haZ~)*r zu?~Q~nx$fuN-i|qT*iq#*pjv!Qs~0qoR~Snkz_H6d*KUD!zZn`xFF_u|7Nx*JIoy6 z7r<6(+!6THXz-D$u2;vtqN#&908%X4x-6kvVa>zRuc~?oi zW6~|-&CMz3ifc96omT9Dh_pG0Qh9k09x#5(@rHdoa1u#Bj#gvo7mK*YEso96c#A8k za$=9l`a0eowHs1vUmQyIC|q?k>4!@vaXdEqc*cz|M@MWihEHX9k1=N0+i}`k*KpZ_ z?HR|$T00bO?c$e8Hdf-0jm^ry83>=$lBdG2DUcUImW-C43i0OV?Cp@aPJucgLsDnw zX5EVAG{;&qiH^=fSXIp)ryQ@NyAm5L#DWq|YGQRA9gLLnl&b6KT$PZH&T1t(Ix*?! zlG9~YG1k#tAA6JAA)_``)6s2H=i8w8{)^XOW3zwH+h5v{^&Q#qt(#B-@*b zf49J!C2yrhYrjv%D5K>+y5Uydvf*zbZ{5-4t@c$6GTw>yWEMD4WMxRF;g=O>SbSIt zGW@K&5!vX!PpPcj&V=G^JxD-Rs#US&b?d+$aAT2lY0`ufrT-t`->r0J4 zUe~w0N#1{UpzV)(-{!uR_f5)vqpn|PcTwL{6C0HK2GNB_ra^S&Y8)=j@REa0HgQO3 zJ5qF6N1HTbE4fAiKU|{?%RF(*a zM6b7`HwyTVmZ*6IsdfF-{2{dbM@bKKhSx@)JTR`V=qBDf4+4w+$H8Gmx9-1V_}pKy zxS8m=mII3Da2Z*mgZi^DHv&s^a0-Y{nIc-k6tY=FCl^z#iY>1bUBa|$6qc${SOxBj z9XykuMq-@h%Sm7b0C(spNk~l5gv3$_iKT`~jFF@g5@StskeJM~H44Mf>j>}R zGGuN_aJAY`WKwI;ZINJ5=M~2~UEeBZ|_TeUF-L9RuFLOveeo zSvj}ZR2a@E8M`t??mrBcD@CSP42$R>1viauWyQ)B>%twCGmG&_Q22QouxeL(IAy>( zhzf9UOrAT|g{#lf0ZG_*cF}ssY|IiSPCxY?cb0VcsC>y?gESnN~8b!Ou0?D zs;FFsOYU!;>8#YZ1BRpfS$ppZ()TO^FAGv7lcOLg+DdnaEg{Azz#pz8Cn%r==I)nV z3xX&+XT@7CDDA$Qh8d|%d_a1MLQHmLK3oCLSxpb6A$(5AJxBKfaH@(L)l(eP!J4Qb z#&H)e&qQ2&1|Xf>|E$Z-+ZLAVtI>yyBc@v zXNYcHZFJ)^M7Ms1$O988)w-!3tBs1qYNKMY*62!W6x*^|qkQvhuN&)Is3v+;!9eAg ztiY_3^ZI`jSOcsx5p}?4hvA38e={2}%jxsvtQXxTQw}uL`^ca4gsk4nS5w4jnQYvjo;n(7~2jV=``!UC<>9 z^`9E8!7tUui=v?ZaR_O=fP15X?-Mw;;-n`CoC`(3+oM`{H2ALz9+SADjaP-f!CL!f zH27x(-!4UAOroTtqdRP1f`>(&lyKE0e9lQuNZLd)?;z(MHfo{EeIQw1i@6QchFsQJ zhGG?;=mH`Wg)q8BR8wX(u+f@3(AeCiwviX)C5qeYA$BqK7L068jm5fgYq*ca=?Hfi z)Q-w{MrK9D6npn6&K|hOZmZnf&{$;XUqvPhO9Ek88^| zx%ILhcT1eNbvQ5F4*Z`9etTTDqcU9B?SiC#*|IN~xU;TB-m6K}U*x?^G~5&Si{`fq!!RH2j=MHNj*+;$$}$qx6mYNa zkMz%0=fh2LTVw1THdS~p*aH7|x%Ecj%dm8xa47DeK=e=?Z6k^@$IjcX+F~upT@Lpk z4pXJ1%DQs5c-Kr5uJo27VQZdnTJI=V?mPu|`>A;UyGT0_PR%wX_MLFV3ay1#NS<>6m< zpPQyEEgsCp>V9+I-Tl(UHf`B4w6Svc3faaEQ|ZBq#Qyp7q=?$BgDTF` zUaWxC5uB|RZzc0mn^|)53eT@K2MvNNlGz-=ATGd4yWiUF&ZHTZdZD|5BFgD+hWd5< zu`;%L7*WYE(GIJCa1E3Hy4ETtEZljNp-m68y-{c&FUfC z8q+4m1PMf#FoFdtb670;>;!j8W7t|W+(q7Q&$X-088s{+zxfK6I za`|I3!+SGgZV3tDv9B@l_EV z;3^iYY}cY4@mNKj*4%m~l779~=z%XI!24w#aNWLQ@uma3>0XX{2cG!BL|tPkq5P$T z&KX|cdqAa5IbQqZSBr;pav9#njb#33?(P58|8w;3Kk=8p|Mll8ca$^zb2i;OTIPtn zQYOgBK88*SxqARxgPrPKkN$gNaNe0ks8|dcNgJd<8i`f>{Z5b((gcnSA;z4HKbtHO zSImd!(X95>7SqUa@BV#Bf42LQ?xSD=Azh_4H81i4`em+N1R33CwikK1i5=LB>3D}3 ztYtmcD6xGPwRV7r@aX6Qlzfdg?BcXd&IqSrIJepBM7EU+z~`LKy9CR%D<>A;X@Q96 z(EV;4SI8ip;<>bcu#uy@P~$b?D937vZooDrye8bH$TmZ3%HEx1lPHDNn%6e|l-6S<4dbAvvWZH~)g z)@I9k+-;^}`Q3KQ@8SwOsqkm2u+vsRH8ctIz9i#7oDn`P6Ejf|fj=B~@La7ew=bB^ zJ0v}70s%r@O3$oA`umR?2w|F@G?{#f2!a5@;H89=$ua|)st&tgKhvE2ry}n=y(b)a zNa_pc5>jlWsl57WWn^RTQS6mE_UY)o-oq=*(mT-Tn)poi|jNa zUfA@;Zy@6lKE*en=r7(UypZAUZw zsJNI|?*Lx5WOa2np~Nc3x4J0I4n*I5{_KwDJ~8Bk&uYFnn6^Gh;Ne@&GCyD6=YvJ~)L*}B^N{ipujiSf$vp$BEM738k{ z(P^e~*L-(oC9AcDoAG!96S-rcG@i8H0mUw0=5xLlA7hY5Nb$A~|JD_Y-FgHD$Uav( zS}9Q89v2nJjV0MacNLh>!7#~zD*Rr+JLqWvR4xaLb)UpV-KE(i3j>s}Q?t>cP0%6X zn+jic21|utwp8lLbJfTBC8+{p+%wRs=LB=_Ezg!#JzH9JWj1BArB%-f=8U2y6sVYC zNaf5x;L(e;>e(MI^#-%0RnNYgad7${Izg}1e=ya&b%W(BqgbWES&IR$S)4)sg28eV z`4Vs3FbR)T9Q<59cUt}Hf}ofgLDTqs#MCmn1L4*lS82~-wq>g@D#4ABad3 zC?FGiCNn`=)mts|XH77fS@^YUSozxntuAPpbYWeMyJ23eVKb{0NSBp(PZm@gC=XXw z9I_Pdz89M60ui#|X@li7g>{t7>WGB7I^bnj9WBSr{m19c(a*urW#MMb%D7G8}RT5>gEh6O|4x za!ruyAh@U1+()PvS>A3rpwXQ8E!O&WLJ$=M(_xGd+9K;tys?7BIbzE6(&KK`hfRX1 zVE3hQc5=^co6*jq69a`UVjl(DOUgR9O4?H^(u6C7^mo|QM~n-pHhA1-HI~CL_W`JJ zA5jG??!+(W${?@#l(As#nv_Ef?(lGn}?hV(iv8V`wcK$|CZOG zlOCh2Mv*GQske#x;j6X$W5e15_jTfj@mBQ66?P&cg*oj|4Z`g@DPd9Vb9P7=@d1)p z+^^{E1oDTKDfLiv)EQKCBH*|ljen+AHYnLwY}3kM3Z-@lwedS$YH)X|Gy^XZ#`sC0 zv4rHRa1UM9ZM>ZzN(mVQH*DZ!oV>BEAcW2#20so+GK) z8}yDM6`?!WFI))IExoRk(QPH9=k3892}H{)vca4WTak$1Oh;e&=W(aYb%I|Yn6skn zO<;HdzmfIcgc7G68Ot<+%mne7xwkR#aY0ElDoeQ6hTf}7Tns%E)EGu@d!*R3kIiCtRn1uM};XN_Dk0~@WeM=qph zWMY6ZBe-;Y#z`p|7O;}-kN9%x^!)>DSpt>6mWAQpgo>3 zO$_wko}ydoA!){&ON>eGZ3yhlOzQ};0-cJEPJg>@`#2LOYNX` z2eQbl3!SrYkg~75IJHYBy0>OPe`ZsE&5v&GhFmId{NaE9`|p1J({H}v++&?O$pYsz zwVYi`2uW7CZr92R}EF=FX0R%dVxdP9m3P67(r zD*!RR#T>()0;S4GKtxvx!Pvd2yrBOL=k8%dyQ6f9T(H?vZ$cJqux0b}f>RnLT4jzE z#&h5oEZe+BUH}I&mdDu@P4)|f%&x;>KD*ypsaIdKsl!o`DyM?!>_U0Eg|POP&h^tl zQS^^}VmUxMW_I&T2VJA7hIe)zf`m*fE3uYA%1)$^Zb_Aj{Z45PVRJ05 z5I|I%AB!svOW6d(6|}~XtiZ+cu#fJV=-&9<z)_F}%bR1F*X^Te~!Wnn?%D?4aAtW*CIUo}TdH5aJOs=6f?p2n9yx;t? zqhWglAQ6B3_T<+w*829a!z{<}_SiI5v)vwDbVo(A$47R9ASLJ_)vs@)%I`6!zFo7~ zE@60B;n;`m%CECErFXJt@yU;fsVuL43FR=4W|#`*N{!D2bF^DI=@=p)?W}G{B6pi~S=}_S-@CvIHT-6Xhb`=R(|PezW^UIx4BtK)(ji6>RfEtz8fvmH zI7!Ipa_xIg2^agF9QbhZmf4Hnb4q(~?OSHpJcwf7GBY7&%CWJ`0^Tws$FkApz4>g) zendM+MW5e0uEK_)ujmaf>nu)z8eoN+^*y+K^r<~yn0GReTg4EOZDOKiC!P}FaN>i5 zIoY*IEI14oYaj%^wKd{0yMLG*J~yJuD7b_{X@1bdOS1{Vj93Y7OO$Do*Z~V5A!#l~ z=R&Z6-rzV?mS>ES{vYgsVXbq5Eb!y(06vl91Si$(0BqO^><>(V%GBo}hBfjuM?% z2F6+j{LV%{{^xvU2;WLzCY%BZV%gNK<--_nLY^Uo^A>s5Y=#5KY!-^`mT}i$HTTPs z^06z?*JtwiQDkyHn8do<7p|std0$!@z->mknf#y=?SHtLnCZ@uKGB_ve`SKja>u>8zA; zi@~--Xf$raVw-#eBH8*n>J}F{J6!c0m*HWvMzRwd$tjHFn6B*QXg9Hw)r?i{h}e~N z@_6ZGxF-*q)z}^mE3B8nIzUhrmN*AY?bP1d@9{DJ_Dy)>`s3Aqi(P&5rdsZ!uC+(_ zSujGt0cW6++{wmKYyGs>Y2}l=@yL>z-*)6#3`>FEmaT#y!hP}&>aZ?+T4S@vb{+8{ z6+UcxMn(I&@B|`+d+IP_!Yp^5#{2hkc}+X2J8ZhBrk%Gh1M$Pdn8>#g>w17#Y;knc zzntm597WIk%Ox|nKSHlJG45SN!hC$mhr{WC@PJB!@R0J;0aqj*iQe(sIg<{5AwE06 zy>DYW)Ix&1PQqWaf6H$R=1qqOfBstWO_|Z3zqT^!{$Jl12^{_6e=UvkT+8Hi`Vh_f zU6O|YVI^$dEx(&K_A-0>1SQ^%8#x2k@q+Zp-!0$^w9zkrchW@*IYkoCyW>*?aZ|q5 zYqx7HTXZ`q9b!6=C`UDXWLHNu`TT`ct5a9}tx=P>z4f)u==x*xEBnUqZmKysW8w{& z)SY+)tL)=1bO?Q%qW%pg0|>jZ&^-+nt$s$Fgvi`~w+=y!4veJk+V>w9m#s(F4dRco z=`&J%lr6KYBAK8|nyB~w*{Zxi3ZKm17Tq=CO|ss)z`_wx=RtiSC#o}2)*JLMTI8Lr z7$Yt_=jfI&><>(_<<4N--pqgoP>Ooo9(#uh@3PwT=P^c?du*Hxh&k~(OC*s#hfZx* zf@6NAW<*F9K^>nI(mF(%CE%(N`UGc-EIPkZ1AeFFcx)3F_{H|P z_e-|3juKagP)%jQHd$UI6_S-={Iny+=?;b!mn+z|0lN3%20BWxUp0h!51&YfM<2Cc zp)Kc^I?_~dPyU=7_O{$A1(_uYv2EgZxd-5;7V)u&WL>yP+^NP`6Z=6XqU?xlUAq?C zqjLv!-$!#`6Y6tdiMbk~k>F%(oC7d%U#gVM;!l`FP#=8IIOvK-&1~aMY#6LHf}1s) zf(~M&s{&;mrIJTpeCi`geH6BbvB}X3HfQaaFR7tF%%awNrTrOo(yZk{ih_>;=hSF+ z+?OUXt?c;kR7Cga2=Kr{E66lxKsV1^1@`6{D~7{cnOYsf^I3nnyQv`5WPvmk5L(Jp z#zIw_)oyh{lf-oA!#k!zNEFtD4&iOTYWT_~Y zN3Y)t*F+wLo9`oHnLi{HzVcC0_Iv9Nsn_c%xhpnH1n@cD3+!=PoP3CdbS9CWzE{0lY#MjktW-l{wEd zE3pw5Hc}dAOR%UYk$N>;(rHWhz!fDD`NJh0wgkTpC0gy_lFHbiBgo+O*X5&3&_U0l zM7?nF=UCQAnVe@L=}UQsE?r%RC+{W;)y#as#5^|BkI6?(?9^|k>vU4lGm^kk__ zI9lUoJ+9^GL6#g)Iv`=#+#8Y_FMJ_nwD!u78;sSJAy*^pBIwkWA>IjFD>G;pmhyOr zdKP=K`W_$H2KNF{;@NaD3$g+RXpjDgPb)Vwe9TP`&nD;7$m`cEu=anNmvFC_Y;^G(UnVV}dNS3vi+>zTO$XlP4%aO%fUyt$=&66`E$*1ITtwgNY z()QW_gB0kN6CL5OK_jdFgKMT#Z+6Ytcf}t)7p}rlLtW$H>m9?Fj---eq6%|RK9bWn zNpe{*k4hfEU&MsLA~9hnd}&AZr>^NUyQ_g`dfk^Et*-R=P%U?hR?#%mL6l8Qs2r~- z`W)^Zu7{!ARUh`u!0^X-nUDXmYFo;jKfX4gnrdgiKx{w6UcDt{E;bidkEG1ZremMf zPFCHtIc?I5=p$Btv6@MInG3!5C9?fB)l1T*r||ktf#|vzqkJ%JCN~}0q3x^gPn#8d z!MK`kGE3Y|U#Nyn%;dEl3a8ARnW(6k{H!Xo;YJU%r1uXJ?Q9?(3%o9ptJPmNnQ7+E zY9V8$Ha++W8o#M}O2*7|KeMa)fs8r9{lc#5{TXvg`>tI>`WoICeWsk%*4K-xKLB7- z552|C69>T>Gj%$6?GfA7IayO`KmO(zDwqFw_4X`(@b2nrU$a?K*>0z)VJ(S2Xyw9Q z^pz_~JADuU!eRLA&{%qq%SH1*c-kp}HL)U$7K9IlvIERRyoAwgPojQhB+x$YV8uXu zay^N^8S43mYf$0SNz|`YPs^Ff=CbM~IkTXvGagcdIUs$%+lj6?p{x2oa%SJ~pIgu! zh(pg-KbJRq`15Vm^9p8T{O8>`y3pUvsQ##6`rM&stKCKOw(i}Ub5UMX>9|t1`8j8T zzq`7oXyz7%o*g1r6%RjK-BUCx&E?fMil)mwmaTTTm|JH3)1D#Ny|^=4j1*05E|3XS zviXppR$Q8B%Kzw7&$O5`+$F5P$onNO2_{i2hw!vG7bzINEsmnk;HwOe?G=9Z5-V5d zjxpn^7q*#mrX@86oc;MD1x=Fe%}RuM%Ouer5ek^>4MZ+fJb_1hYXsEpH$#1VtT}ZA)Qcma zH0>5Ad<=RDPX>EFSRFIY%v`ejanfl&BerY8y-KD0Og?Y9+fM%634E+I-vlCqx@5wo zx7!+(>W9afsqW@Ss-GWcKI!h;Rh`#mPIBLPw0c>WIdPG`*l(-ahH8IUB5py}7JXKr z1dC_)eA})h)H(I3XS(2sjep_cmMJlphgFN(5f0WYhuhnhUwiDSBm5nYlza5qr!Jjh zx?Onp%_TGcWNPUgjJK_DfDC^H!^Ouox-hCfUovOqo=e;{`6sK>%VvhV^Rv|zW%Ew= zm7UccWiw}dS?KNZ^es$cV6JWqKEJd2tFoDBmQ*uS%^dgG&g$Z+=A#P#a;kZE{{Pi- z{hD9?<<(%CnXqtG;P6GcvPC`o8SqQKq8_7TFQ%<$@n^uloTXN^@HcVYb<<4wqWdkT zS);4qBk*C{F7Kvv1nBy5OmH(K@!mYm-i3?E2?oN~6hESNQ2+D$Q>H0l%lNLtpMR_R z57W$&j-P*PGuQ;AZ>vpf4#5}l)_bvX*3py+$*6x!bz&u6WEfWX*dHKIWf=nWx5{XyzODU)}0I%`!8qxAYjll6D*?mHadj-njk) zb5>n{)$H{*E^&H|Pmbf35Gv-#~gnL%Gt^8`7(Z_r>XoZBQ9= zy`h1VN%uCSdqznw zZz!KJqFm|as~P|@WHhcoo^<0Tw2;QRRG-1yNjI+0*`y~ml&>ItLPPp})s~aZ9J981 zx`NL^%L!s-8&w1)CMLbdoJp<1lL zoeMpWtp@WIA>R0BYz;Db|e=^^k z?jFchCoM25{nvmvpBfMGGmoF@m$}2`uEoupN(!?|GB-G3~va&P3 z>ZWV2y=HxI)9S0QS%2-SHMdlMI?rqx_Yq3(BW`a0$Ts}^Kx=jSVqTHI*jl}Q zu_;%&eBaTi#0)jsTKYaWCacCS#b{>mBVy5v#8?{BCzGDZkH}SsAs8{EIsAx6=%1EQ zO#bXEZ@ezpaAh@js_At1_|?*>X5OqL3`UJ!#E&|&L`5iksIAX@;u0&TR5zY#=I73C z^DPq3Y^y$Vs_8E-q)7kN&mw_zX0N?r0~0^kR-LiL%p32F@g3&o^v<0(f59mW7cD;Z z%Bwzb^)=VN)K&=lb-MJEnWUk!ZP{muU!4X zYl3T5Umfsg*{``Z=<1Az@jpANAA6fQDYuxk2;iNa)o0#jHZ^^D4`e&Pdg1A&t9r%h zrm1@U>1Le!PkX9&oo;%^uOAC%0D2>#HvAq!O?vCt>T{=?GglrYElT}1q44!rghHU- z5H?x3c%6gmZw%Jlv>{k?ZE)2Z=$O>C!4-~Es~?PuM@73=pTRS(72~R#&M*td+(y1= zK{M9o-!|^4BWIYerpNS6@+}grAXCWHH>tXHnVCIi6ZryO%#Q}PY0^{AFEbNU{~y<` BvIPJD diff --git a/pyroscope/pprof-bin/src/lib.rs b/pyroscope/pprof-bin/src/lib.rs index 742ac9ab..4ac08148 100644 --- a/pyroscope/pprof-bin/src/lib.rs +++ b/pyroscope/pprof-bin/src/lib.rs @@ -11,6 +11,7 @@ use pprof_pb::querier::v1::Level; use pprof_pb::querier::v1::SelectMergeStacktracesResponse; use prost::Message; use std::collections::{HashMap, HashSet}; +use std::io::stderr; use std::slice::SliceIndex; use std::sync::Mutex; use std::vec::Vec; @@ -18,6 +19,7 @@ use wasm_bindgen::prelude::*; use ch64::city_hash_64; use ch64::read_uint64_le; use ch64::hash_128_to_64; +use std::panic; pub mod pprof_pb { @@ -240,22 +242,7 @@ fn upsert_tree(ctx: &mut HashMap, id: u32) { } } -#[wasm_bindgen] -pub fn merge_prof(id: u32, bytes: &[u8], sample_type: String) { - let mut ctx = CTX.lock().unwrap(); - upsert_tree(&mut ctx, id); - let mut tree = ctx.get_mut(&id).unwrap(); - tree.sample_type = sample_type; - - let prof = Profile::decode(bytes).unwrap(); - merge(&mut tree, &prof); -} - -#[wasm_bindgen] -pub fn merge_tree(id: u32, bytes: &[u8]) { - let mut ctx = CTX.lock().unwrap(); - upsert_tree(&mut ctx, id); - let mut tree = ctx.get_mut(&id).unwrap(); +fn merge_trie(tree: &mut Tree, bytes: &[u8]) { let mut size = 0; let mut offs = 0; (size, offs) = read_uleb128(bytes); @@ -319,26 +306,65 @@ pub fn merge_tree(id: u32, bytes: &[u8]) { } #[wasm_bindgen] -pub fn export_tree(id: u32) -> Vec { - let mut ctx = CTX.lock().unwrap(); - let mut res = SelectMergeStacktracesResponse::default(); - if !ctx.contains_key(&id) { - return res.encode_to_vec(); +pub fn merge_prof(id: u32, bytes: &[u8], sample_type: String) { + let p = panic::catch_unwind(|| { + let mut ctx = CTX.lock().unwrap(); + upsert_tree(&mut ctx, id); + let mut tree = ctx.get_mut(&id).unwrap(); + tree.sample_type = sample_type; + + let prof = Profile::decode(bytes).unwrap(); + merge(&mut tree, &prof); + }); + match p { + Ok(res) => {} + Err(err) => panic!(err) + } - let tree = ctx.get(&id).unwrap(); - if tree.nodes.len() == 0 { - return res.encode_to_vec(); +} + +#[wasm_bindgen] +pub fn merge_tree(id: u32, bytes: &[u8]) { + let result = panic::catch_unwind(|| { + let mut ctx = CTX.lock().unwrap(); + upsert_tree(&mut ctx, id); + let mut tree = ctx.get_mut(&id).unwrap(); + merge_trie(&mut tree, bytes); + 0 + }); + match result { + Ok(res) => {} + Err(err) => panic!(err) } - let mut fg = FlameGraph::default(); - fg.names = tree.names.clone(); - fg.max_self = tree.max_self; - fg.total = 0; - for n in tree.nodes.get(&(0u64)).unwrap().iter() { - fg.total += n.total as i64; +} + +#[wasm_bindgen] +pub fn export_tree(id: u32) -> Vec { + let p = panic::catch_unwind(|| { + let mut ctx = CTX.lock().unwrap(); + let mut res = SelectMergeStacktracesResponse::default(); + if !ctx.contains_key(&id) { + return res.encode_to_vec(); + } + let tree = ctx.get(&id).unwrap(); + if tree.nodes.len() == 0 { + return res.encode_to_vec(); + } + let mut fg = FlameGraph::default(); + fg.names = tree.names.clone(); + fg.max_self = tree.max_self; + fg.total = 0; + for n in tree.nodes.get(&(0u64)).unwrap().iter() { + fg.total += n.total as i64; + } + bfs(tree, &mut fg.levels); + res.flamegraph = Some(fg); + return res.encode_to_vec(); + }); + match p { + Ok(res) => return res, + Err(err) => panic!(err) } - bfs(tree, &mut fg.levels); - res.flamegraph = Some(fg); - res.encode_to_vec() } #[wasm_bindgen] From b5462f86bc13c97b413537dd8dcf9d8100e27c19 Mon Sep 17 00:00:00 2001 From: akvlad Date: Thu, 15 Feb 2024 20:59:15 +0200 Subject: [PATCH 11/12] fix: restrict more than 2M nodes --- pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 84464 -> 84610 bytes pyroscope/pprof-bin/src/lib.rs | 22 +++++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index 21e663e5401fd14f0dac67f9019559ac9aa1fa41..2d96df6859ddf431409c89c418b94ea557629ac4 100644 GIT binary patch delta 11058 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 delta 10956 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, sample_type: String, max_self: i64, + nodes_num: i32 } fn find_node(id: u64, nodes: &Vec) -> i32 { @@ -112,7 +113,7 @@ fn merge(tree: &mut Tree, p: &Profile) { let name = &p.string_table[functions[&location.line[0].function_id].name as usize]; let name_hash = city_hash_64(name.as_bytes()); let node_id = hash_128_to_64(parent_id, name_hash); - if !tree.nodes.contains_key(&parent_id) { + if !tree.nodes.contains_key(&parent_id) && tree.nodes_num < 2000000{ tree.nodes.insert(parent_id, Vec::new()); } let mut slf: u64 = 0; @@ -122,7 +123,10 @@ fn merge(tree: &mut Tree, p: &Profile) { if tree.max_self < slf as i64 { tree.max_self = slf as i64; } - let mut children = tree.nodes.get_mut(&parent_id).unwrap(); + let mut fake_children: Vec = Vec::new(); + let mut children = tree.nodes + .get_mut(&parent_id) + .unwrap_or(&mut fake_children); let n = find_node(node_id, children); if n == -1 { children.push(TreeNodeV2 { @@ -132,9 +136,10 @@ fn merge(tree: &mut Tree, p: &Profile) { slf, total: s.value[u_value_idx] as u64 }); - } else { + } else if tree.nodes_num < 2000000 { children.get_mut(n as usize).unwrap().total += s.value[u_value_idx] as u64; children.get_mut(n as usize).unwrap().slf += slf; + tree.nodes_num += 1; } parent_id = node_id; @@ -237,6 +242,7 @@ fn upsert_tree(ctx: &mut HashMap, id: u32) { nodes: HashMap::new(), sample_type: "".to_string(), max_self: 0, + nodes_num: 1 }, ); } @@ -253,7 +259,7 @@ fn merge_trie(tree: &mut Tree, bytes: &[u8]) { let mut _size: usize = 0; (_size, _offs) = read_uleb128(&bytes[offs..]); offs += _offs; - if !tree.names_map.contains_key(&id) { + if !tree.names_map.contains_key(&id) && tree.names.len() < 2000000 { tree.names.push(String::from_utf8_lossy(&bytes[offs..offs + _size]).to_string()); tree.names_map.insert(id, tree.names.len() - 1); } @@ -282,17 +288,18 @@ fn merge_trie(tree: &mut Tree, bytes: &[u8]) { if n != -1 { tree.nodes.get_mut(&parent_id).unwrap().get_mut(n as usize).unwrap().total += total; tree.nodes.get_mut(&parent_id).unwrap().get_mut(n as usize).unwrap().slf += slf; - } else { + } else if tree.nodes_num < 2000000 { tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { fn_id, parent_id, node_id, slf, total - }) + }); + tree.nodes_num+=1; } - } else { + } else if tree.nodes_num < 2000000 { tree.nodes.insert(parent_id, Vec::new()); tree.nodes.get_mut(&parent_id).unwrap().push(TreeNodeV2 { fn_id, @@ -301,6 +308,7 @@ fn merge_trie(tree: &mut Tree, bytes: &[u8]) { slf, total }); + tree.nodes_num+=1; } } } From b53e279f37e1fd5ffe601040d2ba0561087271e1 Mon Sep 17 00:00:00 2001 From: akvlad Date: Mon, 19 Feb 2024 14:13:29 +0200 Subject: [PATCH 12/12] fix: restrict more than 2M nodes; improve CH request; add dist support for pyroscope v0.2 --- lib/db/maintain/scripts.js | 17 ++++- pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm | Bin 84610 -> 84714 bytes pyroscope/pprof-bin/src/lib.rs | 25 ++++-- pyroscope/pyroscope.js | 88 +++++++++++++++++++--- 4 files changed, 111 insertions(+), 19 deletions(-) diff --git a/lib/db/maintain/scripts.js b/lib/db/maintain/scripts.js index fb506879..7c2aa097 100644 --- a/lib/db/maintain/scripts.js +++ b/lib/db/maintain/scripts.js @@ -400,7 +400,7 @@ module.exports.profiles = [ ADD COLUMN IF NOT EXISTS \`tree\` Array(Tuple(UInt64, UInt64, UInt64, Array(Tuple(String, Int64, Int64)))), ADD COLUMN IF NOT EXISTS \`functions\` Array(Tuple(UInt64, String))`, - 'RENAME TABLE IF EXISTS profiles_mv {{{OnCluster}}} TO profiles_mv_bak', + 'RENAME TABLE IF EXISTS profiles_mv TO profiles_mv_bak {{{OnCluster}}}', `CREATE MATERIALIZED VIEW IF NOT EXISTS profiles_mv {{{OnCluster}}} TO profiles AS SELECT @@ -462,5 +462,18 @@ module.exports.profiles_dist = [ key String, val String, val_id UInt64 - ) ENGINE = Distributed('{{CLUSTER}}','{{DB}}','profiles_series_keys', rand());` + ) ENGINE = Distributed('{{CLUSTER}}','{{DB}}','profiles_series_keys', rand());`, + + `ALTER TABLE profiles_dist {{{OnCluster}}} + ADD COLUMN IF NOT EXISTS \`tree\` Array(Tuple(UInt64, UInt64, UInt64, Array(Tuple(String, Int64, Int64)))), + ADD COLUMN IF NOT EXISTS \`functions\` Array(Tuple(UInt64, String))`, + + `ALTER TABLE profiles_dist {{{OnCluster}}} + ADD COLUMN IF NOT EXISTS \`sample_types_units\` Array(Tuple(String, String))`, + + `ALTER TABLE profiles_series_dist {{{OnCluster}}} + ADD COLUMN IF NOT EXISTS \`sample_types_units\` Array(Tuple(String, String))`, + + `ALTER TABLE profiles_series_gin_dist {{{OnCluster}}} + ADD COLUMN IF NOT EXISTS \`sample_types_units\` Array(Tuple(String, String))` ] diff --git a/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm b/pyroscope/pprof-bin/pkg/pprof_bin_bg.wasm index 2d96df6859ddf431409c89c418b94ea557629ac4..4162f86ed61b7e8a4e3e33055c694b19638cde6c 100644 GIT binary patch delta 9673 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 delta 9532 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 diff --git a/pyroscope/pprof-bin/src/lib.rs b/pyroscope/pprof-bin/src/lib.rs index a87cbee7..da5af679 100644 --- a/pyroscope/pprof-bin/src/lib.rs +++ b/pyroscope/pprof-bin/src/lib.rs @@ -6,20 +6,18 @@ use lazy_static::lazy_static; use pprof_pb::google::v1::Function; use pprof_pb::google::v1::Location; use pprof_pb::google::v1::Profile; -use pprof_pb::querier::v1::FlameGraph; use pprof_pb::querier::v1::Level; +use pprof_pb::querier::v1::FlameGraph; use pprof_pb::querier::v1::SelectMergeStacktracesResponse; +use std::panic; use prost::Message; use std::collections::{HashMap, HashSet}; -use std::io::stderr; use std::slice::SliceIndex; use std::sync::Mutex; use std::vec::Vec; use wasm_bindgen::prelude::*; use ch64::city_hash_64; use ch64::read_uint64_le; -use ch64::hash_128_to_64; -use std::panic; pub mod pprof_pb { @@ -69,6 +67,21 @@ fn find_node(id: u64, nodes: &Vec) -> i32 { n } +fn get_node_id(parent_id: u64, name_hash: u64, level: u16) -> u64 { + let mut node_bytes: [u8; 16] = [0; 16]; + for i in 0..8 { + node_bytes[i] = ((parent_id >> (i * 8)) & 0xFF) as u8; + } + for i in 0..8 { + node_bytes[i+8] = ((name_hash >> (i * 8)) & 0xFF) as u8; + } + let mut _level = level; + if _level > 511 { + _level = 511; + } + (city_hash_64(&node_bytes[0..]) >> 9) | ((_level as u64) << 55) +} + fn merge(tree: &mut Tree, p: &Profile) { let mut functions: HashMap = HashMap::new(); for f in p.function.iter() { @@ -112,7 +125,9 @@ fn merge(tree: &mut Tree, p: &Profile) { let location = locations[&s.location_id[i]]; let name = &p.string_table[functions[&location.line[0].function_id].name as usize]; let name_hash = city_hash_64(name.as_bytes()); - let node_id = hash_128_to_64(parent_id, name_hash); + let node_id = get_node_id( + parent_id, name_hash,(s.location_id.len() - i) as u16 + ); if !tree.nodes.contains_key(&parent_id) && tree.nodes_num < 2000000{ tree.nodes.insert(parent_id, Vec::new()); } diff --git a/pyroscope/pyroscope.js b/pyroscope/pyroscope.js index a16fc4d9..1d4b8c1a 100644 --- a/pyroscope/pyroscope.js +++ b/pyroscope/pyroscope.js @@ -167,10 +167,53 @@ const labelSelectorQuery = (query, labelSelector) => { )) } +const serviceNameSelectorQuery = (labelSelector) => { + const empty = Sql.Eq(new Sql.Raw('1'), new Sql.Raw('1')) + if (!labelSelector || !labelSelector.length || labelSelector === '{}') { + return empty + } + const labelSelectorScript = compiler.ParseScript(labelSelector).rootToken + let conds = null + for (const rule of labelSelectorScript.Children('log_stream_selector_rule')) { + const label = rule.Child('label').value + if (label !== 'service_name') { + continue + } + const val = JSON.parse(rule.Child('quoted_str').value) + let valRul = null + switch (rule.Child('operator').value) { + case '=': + valRul = Sql.Eq(new Sql.Raw('service_name'), Sql.val(val)) + break + case '!=': + valRul = Sql.Ne(new Sql.Raw('service_name'), Sql.val(val)) + break + case '=~': + valRul = Sql.Eq(new Sql.Raw(`match(service_name, ${Sql.quoteVal(val)})`), 1) + break + case '!~': + valRul = Sql.Ne(new Sql.Raw(`match(service_name, ${Sql.quoteVal(val)})`), 1) + } + conds = valRul + } + return conds || empty +} + const selectMergeStacktraces = async (req, res) => { return await selectMergeStacktracesV2(req, res) } +const sqlWithReference = (ref) => { + const res = new Sql.WithReference(ref) + res.toString = function () { + if (this.ref.inline) { + return `(${this.ref.query.toString()}) as ${this.ref.alias}` + } + return this.ref.alias + } + return res +} + const selectMergeStacktracesV2 = async (req, res) => { const dist = clusterName ? '_dist' : '' const typeRegex = parseTypeId(req.body.getProfileTypeid()) @@ -182,15 +225,21 @@ const selectMergeStacktracesV2 = async (req, res) => { ? Math.floor(parseInt(req.body.getEnd()) / 1000) : Math.floor(Date.now() / 1000) const v2 = checkVersion('profiles_v2', (fromTimeSec - 3600) * 1000) + const serviceNameSelector = serviceNameSelectorQuery(sel) + const typeIdSelector = Sql.Eq( + 'type_id', + Sql.val(`${typeRegex.type}:${typeRegex.periodType}:${typeRegex.periodUnit}`) + ) const idxSelect = (new Sql.Select()) .select('fingerprint') .from(`${DATABASE_NAME()}.profiles_series_gin`) .where( Sql.And( Sql.Eq(new Sql.Raw(`has(sample_types_units, (${Sql.quoteVal(typeRegex.sampleType)},${Sql.quoteVal(typeRegex.sampleUnit)}))`), 1), - Sql.Eq('type_id', Sql.val(`${typeRegex.type}:${typeRegex.periodType}:${typeRegex.periodUnit}`)), + typeIdSelector, Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)), - Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)) + Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)), + serviceNameSelector ) ).groupBy('fingerprint') labelSelectorQuery(idxSelect, sel) @@ -205,7 +254,9 @@ const selectMergeStacktracesV2 = async (req, res) => { Sql.And( Sql.Gte('timestamp_ns', new Sql.Raw(Math.floor(fromTimeSec) + '000000000')), Sql.Lte('timestamp_ns', new Sql.Raw(Math.floor(toTimeSec) + '000000000')), - new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxSelect)) + new Sql.In('fingerprint', 'IN', sqlWithReference(withIdxSelect)), + typeIdSelector, + serviceNameSelector )) if (process.env.ADVANCED_PROFILES_MERGE_LIMIT) { rawReq.orderBy(['timestamp_ns', 'desc']).limit(parseInt(process.env.ADVANCED_PROFILES_MERGE_LIMIT)) @@ -214,15 +265,16 @@ const selectMergeStacktracesV2 = async (req, res) => { const joinedReq = (new Sql.Select()).with(withRawReq).select([ new Sql.Raw('(raw.tree.1, raw.tree.2, raw.tree.3, sum(raw.tree.4), sum(raw.tree.5))'), 'tree2' - ]).from(new Sql.WithReference(withRawReq)) + ]).from(sqlWithReference(withRawReq)) .join('raw.tree', 'array') .groupBy(new Sql.Raw('raw.tree.1'), new Sql.Raw('raw.tree.2'), new Sql.Raw('raw.tree.3')) + .orderBy(new Sql.Raw('raw.tree.1')).limit(2000000) const withJoinedReq = new Sql.With('joined', joinedReq, !!clusterName) const joinedAggregatedReq = (new Sql.Select()).select( - [new Sql.Raw('groupArray(tree2)'), 'tree']).from(new Sql.WithReference(withJoinedReq)) + [new Sql.Raw('groupArray(tree2)'), 'tree']).from(sqlWithReference(withJoinedReq)) const functionsReq = (new Sql.Select()).select( [new Sql.Raw('groupUniqArray(raw.functions)'), 'functions2'] - ).from(new Sql.WithReference(withRawReq)).join('raw.functions', 'array') + ).from(sqlWithReference(withRawReq)).join('raw.functions', 'array') let brackLegacy = (new Sql.Select()).select( [new Sql.Raw('[]::Array(String)'), 'legacy'] @@ -236,8 +288,10 @@ const selectMergeStacktracesV2 = async (req, res) => { Sql.And( Sql.Gte('timestamp_ns', new Sql.Raw(Math.floor(fromTimeSec) + '000000000')), Sql.Lte('timestamp_ns', new Sql.Raw(Math.floor(toTimeSec) + '000000000')), - new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxSelect)), - Sql.Eq(new Sql.Raw('empty(tree)'), 1) + new Sql.In('fingerprint', 'IN', sqlWithReference(withIdxSelect)), + Sql.Eq(new Sql.Raw('empty(tree)'), 1), + typeIdSelector, + serviceNameSelector )) if (process.env.ADVANCED_PROFILES_MERGE_LIMIT) { legacy.orderBy(['timestamp_ns', 'desc']).limit(parseInt(process.env.ADVANCED_PROFILES_MERGE_LIMIT)) @@ -245,7 +299,7 @@ const selectMergeStacktracesV2 = async (req, res) => { withLegacy = new Sql.With('legacy', legacy, !!clusterName) brackLegacy = (new Sql.Select()) .select([new Sql.Raw('groupArray(payload)'), 'payloads']) - .from(new Sql.WithReference(withLegacy)) + .from(sqlWithReference(withLegacy)) } brackLegacy = new Sql.Raw(`(${brackLegacy.toString()})`) const brack1 = new Sql.Raw(`(${joinedAggregatedReq.toString()})`) @@ -331,12 +385,18 @@ const selectSeries = async (req, res) => { } const aggregation = _req.getAggregation && _req.getAggregation() + const typeIdSelector = Sql.Eq( + 'type_id', + Sql.val(`${typeID.type}:${typeID.periodType}:${typeID.periodUnit}`)) + const serviceNameSelector = serviceNameSelectorQuery(labelSelector) + const idxReq = (new Sql.Select()) .select(new Sql.Raw('fingerprint')) .from(`${DATABASE_NAME()}.profiles_series_gin`) .where( Sql.And( - Sql.Eq('type_id', Sql.val(`${typeID.type}:${typeID.periodType}:${typeID.periodUnit}`)), + typeIdSelector, + serviceNameSelector, Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)), Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)), Sql.Eq(new Sql.Raw( @@ -361,7 +421,9 @@ const selectSeries = async (req, res) => { .where(Sql.And( new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxReq)), Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)), - Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)) + Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)), + typeIdSelector, + serviceNameSelector )) const withLabelsReq = new Sql.With('labels', labelsReq, !!clusterName) @@ -388,7 +450,9 @@ const selectSeries = async (req, res) => { Sql.And( new Sql.In('p.fingerprint', 'IN', new Sql.WithReference(withIdxReq)), Sql.Gte('p.timestamp_ns', new Sql.Raw(`${fromTimeSec}000000000`)), - Sql.Lt('p.timestamp_ns', new Sql.Raw(`${toTimeSec}000000000`)) + Sql.Lt('p.timestamp_ns', new Sql.Raw(`${toTimeSec}000000000`)), + typeIdSelector, + serviceNameSelector ) ).groupBy('timestamp_ns', 'fingerprint') .orderBy(['fingerprint', 'ASC'], ['timestamp_ns', 'ASC'])