├── .github └── workflows │ └── label.yml ├── .vscode └── settings.json ├── backlog_sysdig.lua ├── backlog_sysdig_all.lua ├── bcc ├── backlog.py ├── backlog_2.py ├── cwnd.py └── ipv6_addr_label.py ├── bgp_mp_unreach_nlri_without_mandatory_atttributes.pcapng ├── bgp_python.py ├── busy.stp ├── cgroups.c ├── coccinelle ├── avoid_assignments_within_checks.cocci ├── bgp_dest_unlock_node.cocci ├── clean_NULL_test.cocci ├── correct_null_test.cocci ├── double-xfree.cocci ├── explicit_null_comparison.cocci ├── remove_double_test.cocci ├── remove_double_test2.cocci ├── replace-bgp_flag_check.cocci ├── return_without_assignment.cocci ├── return_without_parenthesis.cocci ├── s_addr_0_to_inaddrany.cocci ├── short-if-else-xfree.cocci ├── short-if-else.cocci ├── shorthand_operator.cocci ├── useless_code.cocci └── void_no_return.cocci ├── enqueue_to_backlog_drops.stp ├── entropy.stp ├── es.lua ├── fix_elastic_shards.rb ├── get-ruby-method.stp ├── io.stp ├── iptables_synproxy.sh ├── lua-compress-decompress-performance ├── .gitignore ├── compress-libdeflate.lua ├── compress-lzo.lua ├── compress-zlib.lua ├── compress-zstd.lua ├── compress.sh ├── decompress-libdeflate.lua ├── decompress-lzo.lua ├── decompress-zlib.lua ├── decompress-zstd.lua ├── decompress.sh └── go-lzo │ ├── .gitignore │ ├── go.mod │ ├── go.sum │ ├── input.txt │ ├── main.go │ ├── output-lzo.txt │ ├── output-zlib.txt │ └── tools ├── memcached_timeout.stp ├── memcached_tools.rb ├── memcachedlog.lua ├── memcachedtop.lua ├── meminfo.rb ├── mmhistogram ├── mpls.go ├── mysql-trace.stp ├── net_discards.stp ├── netdev_budget.stp ├── netdev_max_backlog.stp ├── nginx-lua-ebpf-socket-spawn-process ├── .gitignore ├── Makefile ├── bin │ ├── h5g-spawner.py │ ├── spawn │ ├── spawn-php-fpm │ ├── spawn-php-fpm.sh │ └── spawn.sh ├── etc │ ├── h5g.js │ └── nginx.conf └── skeleton │ └── etc │ ├── group │ ├── passwd │ └── php-fpm.conf ├── ngx_http_lua_socket_tcp_send.stp ├── redis-cluster-migrate ├── README.md ├── crc16.rb └── migrate.rb ├── redis-module ├── .clang-format ├── .gitignore ├── compile.sh ├── flushdb.c ├── h5g_flushdb.lua ├── hproxy.c ├── hproxy.flushdb.c ├── load.sh ├── redis.conf └── redismodule.h ├── regexp.stp ├── rubygc.stp ├── rubytop.stp ├── rx_discards.stp ├── rx_dropped.stp ├── sentinel.md ├── slow_start_check.stp ├── so_keepalives.stp ├── spam.stp ├── systemd-socket-activation ├── h5g-u1.service ├── h5g-u1.socket ├── nginx.conf ├── php-fpm-u1.conf └── php-fpm-u1.service ├── tcp_abc.stp ├── tcp_abort_on_overflow.md ├── tcp_mem.stp ├── tcp_slow_start.md ├── tcp_timestamps.stp ├── tcp_tstamp_header_len.mov ├── ton_csgo.cfg ├── twemproxy_connections.stp ├── twemproxy_err.stp ├── twemproxy_mbuf.stp ├── twemproxy_messages.stp ├── twemproxy_timeouts.stp ├── twemstats.rb └── validate.rake /.github/workflows/label.yml: -------------------------------------------------------------------------------- 1 | name: Add base branch label 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | 9 | jobs: 10 | label: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions-ecosystem/action-add-labels@v1 15 | with: 16 | labels: | 17 | ${{ github.event.pull_request.base.ref }} 18 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.errorSquiggles": "disabled" 3 | } 4 | -------------------------------------------------------------------------------- /backlog_sysdig.lua: -------------------------------------------------------------------------------- 1 | description = "queue (backlog) utilization" 2 | short_description = "queue utilization" 3 | category = "misc" 4 | 5 | args = 6 | { 7 | { 8 | name = "port", 9 | description = "port to monitor", 10 | argtype = "int" 11 | }, 12 | } 13 | 14 | function on_set_arg(name, val) 15 | port = tonumber(val) 16 | return true 17 | end 18 | 19 | function on_init() 20 | util = nil 21 | sport = chisel.request_field("fd.sport") 22 | queue = chisel.request_field("evt.arg[2]") 23 | sysdig.set_filter("fd.sport="..port.." and evt.type=accept") 24 | chisel.set_interval_s(5) 25 | return true 26 | end 27 | 28 | function on_interval(ts_s, ts_ns, delta) 29 | local list = util 30 | local sum = 0 31 | local num = 0 32 | while list do 33 | sum = sum + list.queue 34 | num = num + 1 35 | list = list.next 36 | end 37 | if num ~= 0 then 38 | print("Utilization for port "..port.." is "..(sum / num).."%") 39 | end 40 | util = nil 41 | return true 42 | end 43 | 44 | function on_event() 45 | util = { next = util, queue = evt.field(queue) } 46 | return true 47 | end 48 | -------------------------------------------------------------------------------- /backlog_sysdig_all.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | backlogs.lua - inspect every port utilization. 3 | 4 | USAGE: sysdig -c backlogs 5 | eg, 6 | 7 | sysdig -c backlogs # show ports utilization every second and stop after 10 seconds 8 | sysdig -c 5 # show ports utilization every 5 second and stop after 10 seconds 9 | sysdig -c '2 20' # show ports utilization every 2 second and stpo after 20 seconds 10 | 11 | By default it will run as sysdig -c '1 10'. 12 | 13 | Copyright (C) 2015 Donatas Abraitis. 14 | 15 | This program is free software: you can redistribute it and/or modify 16 | it under the terms of the GNU General Public License version 2 as 17 | published by the Free Software Foundation. 18 | 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this program. If not, see . 26 | --]] 27 | 28 | -- Chisel description 29 | description = "queue (backlog) utilization" 30 | short_description = "queue utilization" 31 | category = "misc" 32 | 33 | -- Chisel argument list 34 | args = 35 | { 36 | { 37 | name = "refresh", 38 | description = "refresh interval", 39 | optional = true 40 | }, 41 | { 42 | name = "stop", 43 | description = "stop tracing after N seconds", 44 | optional = true 45 | }, 46 | } 47 | 48 | -- Argument notification callback 49 | function on_set_arg(name, val) 50 | if name == "stop" then 51 | stop_after = tonumber(val) 52 | return true 53 | elseif name == "refresh" then 54 | refresh = tonumber(val) 55 | return true 56 | end 57 | return false 58 | end 59 | 60 | -- Initialization callback 61 | function on_init() 62 | util = {} 63 | start_time = os.time() 64 | sport = chisel.request_field("fd.sport") 65 | queuelen = chisel.request_field("evt.arg[3]") 66 | queuemax = chisel.request_field("evt.arg[4]") 67 | syscall = chisel.request_field("evt.type") 68 | return true 69 | end 70 | 71 | -- Capture start callback 72 | function on_capture_start() 73 | islive = sysdig.is_live() 74 | local refresh = refresh or 1 75 | if islive then 76 | chisel.set_interval_s(refresh) 77 | end 78 | print("PORT\t\tBACKLOG\t\tBACKLOGMAX") 79 | return true 80 | end 81 | 82 | -- Interval callback 83 | function on_interval(ts_s, ts_ns, delta) 84 | local stop_after = stop_after or 10 85 | local sum = {} 86 | local num = {} 87 | if (os.time() - start_time) > stop_after then sysdig.end_capture() end 88 | for port,v in pairs(util) do 89 | local list = v 90 | sum[port] = 0 91 | num[port] = 0 92 | local queuemax = list.queuemax 93 | while list do 94 | sum[port] = sum[port] + list.queuelen 95 | num[port] = num[port] + 1 96 | list = list.next 97 | end 98 | if num[port] ~= 0 then 99 | local avg = math.floor(sum[port] / num[port]) 100 | local pct = math.floor(((avg * 100) / queuemax)) or 0 101 | print(port.."\t\t"..avg.." ("..pct.."%)\t\t"..queuemax) 102 | end 103 | end 104 | util = {} 105 | return true 106 | end 107 | 108 | -- Event callback 109 | function on_event() 110 | idx = evt.field(sport) 111 | local syscall = evt.field(syscall) 112 | if idx ~= nil and syscall == "accept" then 113 | util[idx] = { next = util[idx], queuelen = evt.field(queuelen), queuemax = evt.field(queuemax) } 114 | end 115 | return true 116 | end 117 | -------------------------------------------------------------------------------- /bcc/backlog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from bcc import BPF 4 | import ctypes as ct 5 | 6 | bcc_prog = """ 7 | #define KBUILD_MODNAME "backlog" 8 | #include 9 | #include 10 | #include 11 | 12 | void print_stats(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb, 13 | struct request_sock *req, 14 | bool fastopen) 15 | { 16 | u16 lport = sk->__sk_common.skc_num; 17 | bpf_trace_printk("port: %d, backlog: %d, max_backlog: %d\\n", 18 | lport, 19 | sk->sk_ack_backlog, 20 | sk->sk_max_ack_backlog); 21 | } 22 | """ 23 | 24 | b = BPF(text=bcc_prog) 25 | b.attach_kprobe(event="tcp_check_req", fn_name="print_stats") 26 | b.trace_print() 27 | -------------------------------------------------------------------------------- /bcc/backlog_2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from bcc import BPF 4 | import ctypes as ct 5 | 6 | bcc_prog = """ 7 | #define KBUILD_MODNAME "backlog" 8 | #include 9 | #include 10 | #include 11 | 12 | int kprobe__tcp_check_req(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb, 13 | struct request_sock *req, 14 | bool fastopen) 15 | { 16 | u16 lport = sk->__sk_common.skc_num; 17 | bpf_trace_printk("port: %d, backlog: %d, max_backlog: %d\\n", 18 | lport, 19 | sk->sk_ack_backlog, 20 | sk->sk_max_ack_backlog); 21 | return 0; 22 | } 23 | """ 24 | 25 | b = BPF(text=bcc_prog) 26 | b.trace_print() 27 | -------------------------------------------------------------------------------- /bcc/cwnd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from bcc import BPF 4 | from time import sleep 5 | 6 | bcc_prog = """ 7 | #define KBUILD_MODNAME "cwnd" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | BPF_HASH(stats); 14 | 15 | int kprobe__tcp_ack(struct pt_regs *ctx, struct sock *sk) 16 | { 17 | struct tcp_sock *tp = tcp_sk(sk); 18 | u64 *val, zero = 0; 19 | u32 cwnd = 0; 20 | 21 | bpf_probe_read(&cwnd, sizeof(cwnd), (u32 *)(&tp->snd_cwnd)); 22 | val = stats.lookup_or_init((u64 *)&cwnd, &zero); 23 | (*val)++; 24 | 25 | return 0; 26 | } 27 | """ 28 | 29 | b = BPF(text=bcc_prog) 30 | 31 | print("Tracing sending cwnd size... Hit Ctrl-C to end.") 32 | 33 | try: 34 | sleep(99999999) 35 | except KeyboardInterrupt: 36 | pass 37 | 38 | for k, v in b["stats"].items(): 39 | print("%d %d" % (k.value, v.value)) 40 | 41 | -------------------------------------------------------------------------------- /bcc/ipv6_addr_label.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from bcc import BPF 4 | 5 | bcc_prog = """ 6 | #include 7 | #include 8 | #include 9 | 10 | int kretprobe__ipv6_addr_label(struct pt_regs *ctx, 11 | struct net *net, 12 | const struct in6_addr *addr, 13 | int type, 14 | int ifindex) 15 | { 16 | int ret = PT_REGS_RC(ctx); 17 | bpf_trace_printk("ifindex: %d, label: %d\\n", ifindex, ret); 18 | 19 | return 0; 20 | } 21 | """ 22 | 23 | b = BPF(text=bcc_prog) 24 | b.trace_print() 25 | 26 | """ 27 | sshd-5559 [000] d... 167843.542477: : ifindex: -1, label: 0 28 | sshd-5663 [000] dN.. 167863.327959: : ifindex: -1, label: 0 29 | ping6-5707 [000] d... 167873.402854: : ifindex: -1, label: 6 30 | ping6-5707 [000] d... 167873.404414: : ifindex: -1, label: 6 31 | ping6-5707 [000] d... 167874.406325: : ifindex: -1, label: 6 32 | ping6-5707 [000] d... 167875.408850: : ifindex: -1, label: 6 33 | 34 | vagrant@vagrant:~$ ip addrlabel | grep 'label 6' 35 | prefix 2001::/32 label 6 36 | """ 37 | -------------------------------------------------------------------------------- /bgp_mp_unreach_nlri_without_mandatory_atttributes.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/bgp_mp_unreach_nlri_without_mandatory_atttributes.pcapng -------------------------------------------------------------------------------- /bgp_python.py: -------------------------------------------------------------------------------- 1 | # Trivial example on how to send a plain BGP (malformed too) packets. 2 | # Tested with FRR: 3 | # 4 | #router bgp 65001 5 | # neighbor 127.0.0.1 remote-as external 6 | # neighbor 127.0.0.1 passive 7 | # neighbor 127.0.0.1 ebgp-multihop 8 | # neighbor 127.0.0.1 disable-connected-check 9 | # neighbor 127.0.0.1 update-source 127.0.0.2 10 | # neighbor 127.0.0.1 timers 3 90 11 | # neighbor 127.0.0.1 timers connect 1 12 | 13 | import socket 14 | import time 15 | 16 | OPEN = (b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" 17 | b"\xff\xff\x00\x62\x01\x04\xfd\xea\x00\x5a\x0a\x00\x00\x01\x45\x02" 18 | b"\x06\x01\x04\x00\x01\x00\x01\x02\x02\x02\x00\x02\x02\x46\x00\x02" 19 | b"\x06\x41\x04\x00\x00\xfd\xea\x02\x02\x06\x00\x02\x06\x45\x04\x00" 20 | b"\x01\x01\x03\x02\x0e\x49\x0c\x0a\x64\x6f\x6e\x61\x74\x61\x73\x2d" 21 | b"\x70\x63\x00\x02\x04\x40\x02\x00\x78\x02\x09\x47\x07\x00\x01\x01" 22 | b"\x80\x00\x00\x00") 23 | 24 | KEEPALIVE = (b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" 25 | b"\xff\xff\xff\xff\xff\xff\x00\x13\x04") 26 | 27 | #UPDATE = bytearray.fromhex("ffffffffffffffffffffffffffffffff002b0200000003c0ff00010100eb00ac100b0b001ad908ac100b0b") 28 | #UPDATE = bytearray.fromhex("ffffffffffffffffffffffffffffffff002c020000000a810f0700020202000000021602000040002400020f0f0f0f0f") 29 | #UPDATE = bytearray.fromhex("ffffffffffffffffffffffffffffffff0064020000002e04280f003600031100010a0000290002001a0000200a000076400101005002000602010002fde9c0f50f030c000000ffffff0000080002fe110000400dc0160900060000ffffffffffffffffffffffffff004d0200000d0a00000003e800000000ff0010060400000a02068000ff0101010208490604000000f6ff00001000000003e87600000000ff00100604000000f6ff00006204") 30 | #UPDATE = bytearray.fromhex("ffffffffffffffffffffffffffffffff0030060105000100000000000000000000010101010a01010101e9fffffffffffffffffff7ffffffffff10ffffffffffffffffffffffffffffffffffff006402000000002e9000020019ffe10000000000000101") 31 | #UPDATE = bytearray.fromhex("ffffffffffffffffffffffffffffffff0030060105000100000000000000000000010101010a01010101e9fffffffffffffffffff7ffffffffff10ffffffffffffffffffffffffffffffffffff006402000000002e9000020019ffe10000000000000101") 32 | UPDATE = bytearray.fromhex("ffffffffffffffffffffffffffffffff002c06004916110004ff002c06004916110004000002810f041f00020220ffffffffff000002810f041f00020220ffffffffffffffffffffff05") 33 | 34 | while True: 35 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 36 | s.connect(('127.0.0.2', 179)) 37 | s.send(OPEN) 38 | data = s.recv(4096) 39 | s.send(KEEPALIVE) 40 | data = s.recv(4096) 41 | s.send(UPDATE) 42 | data = s.recv(4096) 43 | s.close() 44 | time.sleep(1) 45 | 46 | -------------------------------------------------------------------------------- /busy.stp: -------------------------------------------------------------------------------- 1 | # unlinkat(AT_FDCWD, "/home/u590669019/public_html/includes", AT_REMOVEDIR) = -1 EBUSY (Device or resource busy) 2 | # stap ok.stp /home/u590669019/public_html/includes 3 | # [27596]<-php-cgi 4 | # [28167]<-php-cgi 5 | # @ton31337 6 | 7 | probe kernel.function("vfs_read"),kernel.function("vfs_write") 8 | { 9 | mnt = reverse_path_walk($file->f_path->mnt->mnt_mountpoint); 10 | dentry = reverse_path_walk($file->f_path->dentry); 11 | mnt_t = "/" . mnt; 12 | if(mnt == "/") 13 | mnt_t = " " 14 | 15 | path = mnt_t . "/" . dentry; 16 | if(path == @1) 17 | printf("[%d] <- %s\n", pid(), execname()); 18 | } 19 | -------------------------------------------------------------------------------- /cgroups.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * Assumes cgroup is mounted at /cgroup using 9 | * 10 | * mount -t cgroup -o none,name=test none /cgroup 11 | * gcc a.c -o cgroup -lcgroup 12 | */ 13 | int main() 14 | { 15 | int ret; 16 | struct cgroup *cgroup; 17 | struct cgroup_controller *cgc; 18 | 19 | ret = cgroup_init(); 20 | if (ret) { 21 | printf("FAIL: cgroup_init failed with %s\n", cgroup_strerror(ret)); 22 | exit(3); 23 | } 24 | 25 | cgroup = cgroup_new_cgroup("/mysql/donatas4"); 26 | if (!cgroup) { 27 | printf("FAIL: cgroup_new_cgroup failed\n"); 28 | exit(3); 29 | } 30 | 31 | cgc = cgroup_add_controller(cgroup, "cpu"); 32 | if (!cgc) { 33 | printf("FAIL: cgroup_add_controller failed\n"); 34 | exit(3); 35 | } 36 | 37 | ret = cgroup_set_uid_gid(cgroup, 1000, 1000, 1000, 1000); 38 | if (ret) { 39 | printf("FAIL: cgroup_set_uid_gid failed with %s\n", cgroup_strerror(ret)); 40 | } 41 | 42 | ret = cgroup_create_cgroup(cgroup, 1); 43 | if (ret) { 44 | printf("FAIL: cgroup_create_cgroup failed with %s\n", cgroup_strerror(ret)); 45 | exit(3); 46 | } 47 | 48 | if (access("/sys/fs/cgroup/cpu/mysql/donatas/tasks", F_OK) == 0) 49 | printf("PASS\n"); 50 | else 51 | printf("Failed to create cgroup\n"); 52 | 53 | pid_t tid = syscall(SYS_gettid); 54 | ret = cgroup_attach_task_pid(cgroup, tid); 55 | printf("attach task: %d\n", tid); 56 | 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /coccinelle/avoid_assignments_within_checks.cocci: -------------------------------------------------------------------------------- 1 | @else_if@ 2 | expression E1, E2; 3 | statement S1, S2; 4 | position p; 5 | @@ 6 | 7 | if (E1) S1 else if@p (E2) S2 8 | 9 | @if_equal@ 10 | identifier I; 11 | expression E; 12 | statement S1, S2; 13 | constant C; 14 | position p != else_if.p; 15 | @@ 16 | 17 | ( 18 | - if@p ((I = E) == C) 19 | + I = E; if (I == C) 20 | S1 21 | | 22 | - if@p ((I = E) == C) 23 | + I = E; if (I == C) 24 | S1 else S2 25 | | 26 | - if@p ((I = E) != C) 27 | + I = E; if (I != C) 28 | S1 29 | | 30 | - if@p ((I = E) != C) 31 | + I = E; if (I != C) 32 | S1 else S2 33 | | 34 | - if@p ((I = E) < C) 35 | + I = E; if (I < C) 36 | S1 37 | | 38 | - if@p ((I = E) < C) 39 | + I = E; if (I < C) 40 | S1 else S2 41 | | 42 | - if@p ((I = E) <= C) 43 | + I = E; if (I <= C) 44 | S1 45 | | 46 | - if@p ((I = E) <= C) 47 | + I = E; if (I <= C) 48 | S1 else S2 49 | | 50 | - if@p ((I = E) > C) 51 | + I = E; if (I > C) 52 | S1 53 | | 54 | - if@p ((I = E) > C) 55 | + I = E; if (I > C) 56 | S1 else S2 57 | | 58 | - if@p ((I = E) >= C) 59 | + I = E; if (I >= C) 60 | S1 61 | | 62 | - if@p ((I = E) >= C) 63 | + I = E; if (I >= C) 64 | S1 else S2 65 | ) 66 | -------------------------------------------------------------------------------- /coccinelle/bgp_dest_unlock_node.cocci: -------------------------------------------------------------------------------- 1 | // Check for missing bgp_dest_unlock_node. 2 | // bgp_node_lookup/bgp_node_get advances locks. 3 | 4 | @r1@ 5 | identifier dest; 6 | position p1; 7 | @@ 8 | 9 | dest = 10 | ( 11 | bgp_node_lookup@p1(...) 12 | | 13 | bgp_node_get@p1(...) 14 | ) 15 | ... 16 | when != bgp_dest_unlock_node 17 | 18 | @r2@ 19 | identifier dest; 20 | position p1; 21 | statement S1,S; 22 | @@ 23 | 24 | dest = bgp_node_lookup(...) 25 | ... 26 | when != if (...) bgp_dest_unlock_node(dest); 27 | when != if (!dest) S1 28 | bgp_dest_unlock_node(dest@p1); 29 | 30 | @script:python@ 31 | //x1 << r1.p1; 32 | x2 << r2.p1; 33 | @@ 34 | 35 | //coccilib.report.print_report(x1[0],"Missing bgp_dest_unlock_node") 36 | coccilib.report.print_report(x2[0],"Missing NULL check before bgp_dest_unlock_node") 37 | -------------------------------------------------------------------------------- /coccinelle/clean_NULL_test.cocci: -------------------------------------------------------------------------------- 1 | @@ 2 | expression E; 3 | statement S; 4 | @@ 5 | - if (E == NULL) 6 | + if (!E) 7 | S 8 | -------------------------------------------------------------------------------- /coccinelle/correct_null_test.cocci: -------------------------------------------------------------------------------- 1 | // Correct test against NULL 2 | 3 | @r@ 4 | expression *x; 5 | expression e; 6 | identifier l; 7 | position p2,p3; 8 | @@ 9 | 10 | if (x@p3 == NULL || ...) { 11 | ... when forall 12 | return ...; } 13 | ... when != goto l; 14 | when != x = e 15 | when != &x 16 | x@p2 == NULL 17 | 18 | @single@ 19 | position r.p2 != r.p3; 20 | expression x; 21 | @@ 22 | 23 | x@p2 == NULL 24 | 25 | @ok depends on single@ 26 | expression *x; 27 | position any r.p3; 28 | position r.p2; 29 | statement S; 30 | @@ 31 | 32 | ... when != x@p3 == NULL 33 | x@p2 == NULL 34 | 35 | @depends on !ok && single@ 36 | position r.p2,r.p3; 37 | expression *x; 38 | @@ 39 | 40 | *x@p3 == NULL 41 | ... 42 | *x@p2 == NULL 43 | -------------------------------------------------------------------------------- /coccinelle/double-xfree.cocci: -------------------------------------------------------------------------------- 1 | // Double NULL is not needed. It's already handled in XFREE. 2 | // Copyright: (C) 2020 Donatas Abraitis. GPLv2. 3 | 4 | @@ 5 | type T; 6 | T *pointer; 7 | @@ 8 | 9 | XFREE(..., pointer); 10 | - pointer = NULL; 11 | -------------------------------------------------------------------------------- /coccinelle/explicit_null_comparison.cocci: -------------------------------------------------------------------------------- 1 | @replace_rule@ 2 | expression e; 3 | @@ 4 | 5 | -e == NULL 6 | + !e 7 | -------------------------------------------------------------------------------- /coccinelle/remove_double_test.cocci: -------------------------------------------------------------------------------- 1 | // Remove double test 2 | 3 | @expression@ 4 | expression E; 5 | @@ 6 | 7 | * E 8 | || ... || E 9 | 10 | @expression@ 11 | expression E; 12 | @@ 13 | 14 | * E 15 | && ... && E 16 | -------------------------------------------------------------------------------- /coccinelle/remove_double_test2.cocci: -------------------------------------------------------------------------------- 1 | // Remove double test 2 | 3 | @r exists@ 4 | local idexpression x; 5 | expression E; 6 | position p1,p2; 7 | @@ 8 | 9 | if (x@p1 == NULL || ...) { ... when forall 10 | return ...; } 11 | ... when != \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\) 12 | when != &x 13 | ( 14 | x@p2 == NULL 15 | | 16 | x@p2 != NULL 17 | ) 18 | 19 | // another path to the test that is not through p1? 20 | 21 | @s exists@ 22 | local idexpression r.x; 23 | position r.p1,r.p2; 24 | @@ 25 | 26 | ... when != x@p1 27 | ( 28 | x@p2 == NULL 29 | | 30 | x@p2 != NULL 31 | ) 32 | 33 | // another path to the test from p1? 34 | 35 | @t exists@ 36 | local idexpression x; 37 | position r.p1,r.p2; 38 | @@ 39 | 40 | if (x@p1 == NULL || ...) { ... x@p2 ... when any 41 | return ...; } 42 | 43 | // another path to the test containing an assignment? 44 | 45 | @u exists@ 46 | local idexpression x; 47 | expression E; 48 | position r.p1,r.p2; 49 | @@ 50 | 51 | if (x@p1 == NULL || ...) { ... when forall 52 | return ...; } 53 | ... 54 | \(x=E\|x--\|x++\|--x\|++x\|x-=E\|x+=E\|x|=E\|x&=E\|&x\) 55 | ... when != x@p1 56 | when any 57 | ( 58 | x@p2 == NULL 59 | | 60 | x@p2 != NULL 61 | ) 62 | 63 | @fix depends on !s && !t && !u@ 64 | position r.p2; 65 | expression x,E; 66 | statement S1,S2; 67 | @@ 68 | 69 | ( 70 | - if ((x@p2 != NULL) || ...) 71 | S1 72 | | 73 | - if ((x@p2 != NULL) || ...) 74 | S1 75 | - else S2 76 | | 77 | - (x@p2 != NULL) && E 78 | + E 79 | | 80 | - (x@p2 == NULL) || E 81 | + E 82 | | 83 | - if ((x@p2 == NULL) && ...) S1 84 | | 85 | - if ((x@p2 == NULL) && ...) S1 else 86 | S2 87 | | 88 | - BUG_ON(x@p2 == NULL); 89 | ) 90 | 91 | @script:python depends on !s && !t && !u && !fix@ 92 | p1 << r.p1; 93 | p2 << r.p2; 94 | @@ 95 | print "* TODO [[view:%s::face=ovl-face1::linb=%s::colb=%s::cole=%s][%s::%s]]" % (p1[0].file,p1[0].line,p1[0].column,p1[0].column_end,p1[0].file,p1[0].line) 96 | for i in p2: 97 | print "[[view:%s::face=ovl-face3::linb=%s::colb=%s::cole=%s][retest::%s]]" % (i.file,i.line,i.column,i.column_end,i.line) 98 | -------------------------------------------------------------------------------- /coccinelle/replace-bgp_flag_check.cocci: -------------------------------------------------------------------------------- 1 | // Replace bgp_flag_* to [UN]SET/CHECK_FLAG macros. 2 | // Copyright: (C) 2020 Donatas Abraitis. GPLv2. 3 | 4 | @@ 5 | expression E1, E2; 6 | @@ 7 | 8 | ( 9 | - bgp_flag_check(E1, E2) 10 | + CHECK_FLAG(E1->flags, E2) 11 | | 12 | - bgp_flag_set(E1, E2) 13 | + SET_FLAG(E1->flags, E2) 14 | | 15 | - bgp_flag_unset(E1, E2) 16 | + UNSET_FLAG(E1->flags, E2) 17 | ) 18 | -------------------------------------------------------------------------------- /coccinelle/return_without_assignment.cocci: -------------------------------------------------------------------------------- 1 | @@ 2 | expression ret; 3 | identifier f; 4 | @@ 5 | 6 | -ret = 7 | +return 8 | f(...); 9 | -return ret; 10 | -------------------------------------------------------------------------------- /coccinelle/return_without_parenthesis.cocci: -------------------------------------------------------------------------------- 1 | // Copyright: (C) 2020 Donatas Abraitis. GPLv2. 2 | 3 | @@ 4 | constant C; 5 | @@ 6 | 7 | - return (C); 8 | + return C; 9 | -------------------------------------------------------------------------------- /coccinelle/s_addr_0_to_inaddrany.cocci: -------------------------------------------------------------------------------- 1 | // No more magic numbers for s_addr 2 | // Copyright: (C) 2020 Donatas Abraitis. GPLv2. 3 | 4 | @@ 5 | expression E; 6 | @@ 7 | 8 | ( 9 | - E.s_addr == 0 10 | + E.s_addr == INADDR_ANY 11 | | 12 | - E.s_addr != 0 13 | + E.s_addr != INADDR_ANY 14 | | 15 | - E.s_addr = 0 16 | + E.s_addr = INADDR_ANY 17 | ) 18 | -------------------------------------------------------------------------------- /coccinelle/short-if-else-xfree.cocci: -------------------------------------------------------------------------------- 1 | // Drop parentheses in short-if-else branches (XFREE) 2 | // Copyright: (C) 2020 Donatas Abraitis. GPLv2. 3 | 4 | @@ 5 | expression e, t; 6 | @@ 7 | 8 | - if (e) { 9 | + if (e) 10 | XFREE(t, e); 11 | - e = NULL; 12 | - } 13 | -------------------------------------------------------------------------------- /coccinelle/short-if-else.cocci: -------------------------------------------------------------------------------- 1 | // Drop parentheses in short-if-else branches 2 | // Copyright: (C) 2020 Donatas Abraitis. GPLv2. 3 | 4 | @@ 5 | expression E; 6 | @@ 7 | 8 | ( 9 | if (...) 10 | - { 11 | E; 12 | - } 13 | | 14 | if (...) 15 | { 16 | E; 17 | } else 18 | - { 19 | E; 20 | - } 21 | | 22 | if (...) 23 | E; 24 | else 25 | - { 26 | E; 27 | - } 28 | | 29 | if (...) 30 | - { 31 | E; 32 | - } 33 | else 34 | - { 35 | E; 36 | - } 37 | ) 38 | -------------------------------------------------------------------------------- /coccinelle/shorthand_operator.cocci: -------------------------------------------------------------------------------- 1 | @@ 2 | identifier data; 3 | constant x; 4 | @@ 5 | 6 | ( 7 | - data = data + x 8 | + data += x 9 | | 10 | - data = data - x 11 | + data -= x 12 | ) 13 | -------------------------------------------------------------------------------- /coccinelle/useless_code.cocci: -------------------------------------------------------------------------------- 1 | // Remove useless code 2 | 3 | @a forall@ 4 | idexpression *x; 5 | identifier f != ERR_PTR; 6 | position p1,p2; 7 | @@ 8 | 9 | x@p1 = f(...) 10 | ... when != x 11 | ( 12 | x = f(...,<+...x...+>,...) 13 | | 14 | x@p2 = f(...) 15 | ) 16 | 17 | @script:python@ 18 | p1 << a.p1; 19 | p2 << a.p2; 20 | @@ 21 | if (p1[0].line == p2[0].line): 22 | cocci.include_match(False) 23 | @@ 24 | idexpression *x; 25 | identifier f; 26 | position a.p1,a.p2; 27 | @@ 28 | *x@p1 = f(...) 29 | ... 30 | *x@p2 = f(...) 31 | -------------------------------------------------------------------------------- /coccinelle/void_no_return.cocci: -------------------------------------------------------------------------------- 1 | @@ 2 | identifier f; 3 | expression e; 4 | @@ 5 | void f(...) { 6 | ... 7 | - return 8 | e; 9 | } 10 | -------------------------------------------------------------------------------- /enqueue_to_backlog_drops.stp: -------------------------------------------------------------------------------- 1 | # @ton31337 2 | # This counter 'dropped' should not be used with device driver. Do not confuse with rx_dropped 3 | # in sk_buff. This is struct softnet_stat. 4 | # cat /proc/net/softnet_stat (2nd column - netdev_max_backlog drops) 5 | 6 | probe begin 7 | { 8 | ansi_clear_screen(); 9 | printf("Probing...Type CTRL+C to stop probing.\n"); 10 | } 11 | 12 | # dev.c:2997 13 | # __get_cpu_var(netdev_rx_stat).dropped++; 14 | probe kernel.statement("enqueue_to_backlog@net/core/dev.c:2997") 15 | { 16 | printf("#### %s (%s) ####\n", ctime(gettimeofday_s()), ppfunc()); 17 | print_backtrace(); 18 | } 19 | -------------------------------------------------------------------------------- /entropy.stp: -------------------------------------------------------------------------------- 1 | # show how entropy is used in linux.. 2 | # @ton31337 3 | 4 | global counter; 5 | 6 | function print_head() 7 | { 8 | ansi_clear_screen(); 9 | counter = 0; 10 | println("Probing...Type CTRL+C to stop probing."); 11 | } 12 | 13 | probe begin { print_head(); } 14 | 15 | probe kernel.function("extract_entropy").return 16 | { 17 | if (counter++ > 30) { 18 | print_head(); 19 | } 20 | 21 | delta_time = gettimeofday_us() - @entry(gettimeofday_us()); 22 | pool_name = kernel_string(@cast($r, "entropy_store")->name); 23 | entropy_counter = $r->entropy_count; 24 | 25 | printf("%s %25s (%d) %8d %8d\t%s\n", 26 | ctime(gettimeofday_s()), 27 | execname(), 28 | tid(), 29 | delta_time, 30 | entropy_counter, 31 | pool_name); 32 | } 33 | -------------------------------------------------------------------------------- /es.lua: -------------------------------------------------------------------------------- 1 | description = "total connections to es" 2 | short_description = "total connections to es" 3 | category = "misc" 4 | 5 | args = 6 | { 7 | { 8 | name = "refresh", 9 | description = "", 10 | argtype = "int" 11 | }, 12 | } 13 | 14 | function on_set_arg(name, val) 15 | refresh = tonumber(val) 16 | return true 17 | end 18 | 19 | function on_init() 20 | _accepts = {} 21 | _total = 0 22 | etime = chisel.request_field("evt.latency") 23 | ctime = chisel.request_field("evt.time") 24 | src_ip = chisel.request_field("fd.cip") 25 | sysdig.set_filter("fd.sport=9200 and evt.type=accept") 26 | chisel.set_interval_s(refresh) 27 | return true 28 | end 29 | 30 | function on_interval(ts_s, ts_ns, delta) 31 | table.sort(_accepts) 32 | for k,v in pairs(_accepts) do 33 | print(k.."\t".._accepts[k]) 34 | end 35 | print("Total connections: ".._total.."/"..refresh.."s\n") 36 | _accepts = {} 37 | _total = 0 38 | return true 39 | end 40 | 41 | function on_event() 42 | local src_ip = evt.field(src_ip) 43 | _accepts[src_ip] = (_accepts[src_ip] or 0) + 1 44 | _total = _total + 1 45 | return true 46 | end 47 | -------------------------------------------------------------------------------- /fix_elastic_shards.rb: -------------------------------------------------------------------------------- 1 | NODES = [ 2 | "node1", 3 | "node2", 4 | "node3" 5 | ] 6 | 7 | commands = [] 8 | `curl -s localhost:9200/_cat/shards | grep UNASSIGNED`.each_line do |shard| 9 | res = shard.split(' ') 10 | idx = res[0] 11 | shrd = res[1] 12 | 13 | current_hosts = [] 14 | `curl -s localhost:9200/_cat/shards | grep STARTED`.each_line do |line| 15 | res = line.split(' ') 16 | if res[0] == idx && res[1] == shrd 17 | current_hosts << res[7] 18 | end 19 | end 20 | 21 | (NODES - current_hosts).each do |host| 22 | commands << "curl -XPOST -d '{ \"commands\" : [ { \"allocate\" : { \"index\" : \"#{idx}\", \"shard\": #{shrd}, \"node\": \"#{host}\" } } ] }'" 23 | end 24 | 25 | end 26 | 27 | commands.uniq.each do |cmd| 28 | print "#{cmd}\n" 29 | `#{cmd} 'http://localhost:9200/_cluster/reroute?pretty' &>/dev/null` 30 | end 31 | -------------------------------------------------------------------------------- /get-ruby-method.stp: -------------------------------------------------------------------------------- 1 | # @ton31337 2 | global count; 3 | 4 | probe process("/opt/rbenv/versions/2.2.0/bin/ruby").function("rb_call0").return, 5 | process("/opt/rbenv/versions/2.2.0/bin/ruby").function("rb_add_method").return 6 | { 7 | count[$mid,pid()]++; 8 | } 9 | 10 | probe timer.s(5) 11 | { 12 | ansi_clear_screen(); 13 | foreach([mid,pid] in count- limit 1) { 14 | printf("mid: %d, pid: %d, count: %d\n", mid, pid, count[mid,pid]); 15 | system(sprintf("gdb -p %d --batch -ex 'call rb_id2name(%d)' 2>/dev/null | awk '{ if($0 ~ / = /) { print $4; } }'", 16 | pid, mid)) 17 | } 18 | delete count; 19 | } 20 | -------------------------------------------------------------------------------- /io.stp: -------------------------------------------------------------------------------- 1 | # Show IO by pid 2 | # Compile: 3 | # stap -DSTP_NO_OVERLOAD io.stp -p4 -m io 4 | # Run: 5 | # staprun io.ko -x refresh= 6 | # @ton31337 7 | 8 | global io; 9 | global MIN_IO=8192; 10 | global refresh=5; 11 | global refresh_count=0; 12 | 13 | function header() 14 | { 15 | ansi_clear_screen(); 16 | printf("Probing...Type CTRL+C to stop probing.\n"); 17 | printf("D\tSIZE\tCOUNT\tPATH\n"); 18 | } 19 | 20 | probe begin { header(); } 21 | probe kernel.function("vfs_read"), kernel.function("vfs_write") 22 | { 23 | dentry = reverse_path_walk($file->f_path->dentry); 24 | op = 1; 25 | if(ppfunc() == "vfs_write") 26 | op = 2; 27 | 28 | if((dentry != "") && 29 | pid() == target()) { 30 | 31 | io[$file, op] += $count; 32 | } 33 | } 34 | 35 | probe timer.s(1) 36 | { 37 | if(refresh_count++ % refresh) next 38 | header(); 39 | foreach([file, direct] in io- limit 10) { 40 | try { 41 | count_t = @cast(file, "file")->f_count->counter; 42 | path_t = reverse_path_walk(@cast(file, "file")->f_path->dentry); 43 | mnt_t = reverse_path_walk(@cast(file, "file")->f_path->mnt->mnt_root); 44 | if(mnt_t == "/") 45 | mnt_t = " " 46 | else 47 | mnt_t = "/" . mnt_t; 48 | if(path_t != "" && (io[file,direct] > MIN_IO)) 49 | printf("%d\t%d\t%d\t%s/%s\n", direct, io[file,direct], count_t, mnt_t, path_t); 50 | } catch(err) {} 51 | } 52 | } 53 | 54 | probe end 55 | { 56 | printf("Hope you are doing well ;-)\n"); 57 | delete refresh_count; 58 | delete io; 59 | } 60 | -------------------------------------------------------------------------------- /iptables_synproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # iptables SYNPROXY target usage example 4 | # (support added in iptables v1.4.21) 5 | # 6 | # WARNING: This script is for localhost INPUT 7 | # REMEMBER to change INPUT to FORWARD 8 | # if you are using this on a firewall 9 | # 10 | # Author: Jesper Dangaard Brouer 11 | 12 | #export IPTABLES_CMD= 13 | default_ipt_cmd="/usr/local/sbin/iptables" 14 | 15 | if [ "$EUID" -ne 0 ]; then 16 | # Can be run as normal user, will just use "sudo" 17 | export su=sudo 18 | fi 19 | 20 | function usage() { 21 | echo "" 22 | echo " $0 - SYNPROXY setup script" 23 | echo "" 24 | echo "Usage:" 25 | echo "------" 26 | echo " Script : $0" 27 | echo " Parameters: [-vf] -i interface -p dest-port" 28 | echo "" 29 | echo " -v : verbose" 30 | echo " -i : Interface/device" 31 | echo " -p : Destination TCP port" 32 | echo " -f : Flush rules before creating new rules" 33 | echo "" 34 | } 35 | 36 | ## --- Parse command line arguments --- 37 | while getopts ":i:p:vf" option; do 38 | case $option in 39 | i) 40 | DEV=$OPTARG 41 | ;; 42 | p) 43 | PORT=$OPTARG 44 | ;; 45 | v) 46 | VERBOSE=yes 47 | ;; 48 | f) 49 | FLUSH=yes 50 | ;; 51 | ?|*) 52 | echo "" 53 | echo "[ERROR] Unknown parameter \"$OPTARG\"" 54 | usage 55 | exit 2 56 | esac 57 | done 58 | shift $[ OPTIND - 1 ] 59 | 60 | if [ -z "$DEV" ]; then 61 | usage 62 | echo "ERROR: no device specified" 63 | exit 1 64 | fi 65 | 66 | if [ -z "$PORT" ]; then 67 | usage 68 | echo "ERROR: no port specified" 69 | exit 1 70 | fi 71 | 72 | # Extra checking for iptables 73 | if [ -z "$IPTABLES_CMD" ]; then 74 | echo "WARNING: Shell env variable IPTABLES_CMD is undefined" 75 | export IPTABLES_CMD=${default_ipt_cmd} 76 | echo "WARNING: Fallback to default IPTABLES_CMD=${default_ipt_cmd}" 77 | fi 78 | 79 | # 80 | # A shell iptables function wrapper 81 | # 82 | iptables() { 83 | $su $IPTABLES_CMD "$@" 84 | local result=$? 85 | if [ ${result} -gt 0 ]; then 86 | echo "WARNING -- Error (${result}) when executing the iptables command:" 87 | echo " \"iptables $@\"" 88 | else 89 | if [ -n "${VERBOSE}" ]; then 90 | echo "iptables $@" 91 | fi 92 | fi 93 | } 94 | 95 | # Cleanup before applying our rules 96 | if [ -n "$FLUSH" ]; then 97 | iptables -t raw -F 98 | iptables -t raw -X 99 | iptables -F 100 | iptables -X 101 | fi 102 | 103 | # SYNPROXY works on untracked conntracks 104 | # it will create the appropiate conntrack proxied TCP conn 105 | # NOTICE: table "raw" 106 | iptables -t raw -I PREROUTING -i $DEV -p tcp -m tcp --syn \ 107 | --dport $PORT -j CT --notrack 108 | 109 | # Catching state 110 | # UNTRACKED == SYN packets 111 | # INVALID == ACK from 3WHS 112 | iptables -A INPUT -i $DEV -p tcp -m tcp --dport $PORT \ 113 | -m state --state INVALID,UNTRACKED \ 114 | -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 115 | 116 | # Drop rest of state INVALID 117 | # This will e.g. catch SYN-ACK packet attacks 118 | iptables -A INPUT -i $DEV -p tcp -m tcp --dport $PORT \ 119 | -m state --state INVALID -j DROP 120 | 121 | # More strict conntrack handling to get unknown ACKs (from 3WHS) to be 122 | # marked as INVALID state (else a conntrack is just created) 123 | # 124 | $su /sbin/sysctl -w net/netfilter/nf_conntrack_tcp_loose=0 125 | 126 | # Enable timestamping, because SYN cookies uses TCP options field 127 | $su /sbin/sysctl -w net/ipv4/tcp_timestamps=1 128 | 129 | # Adjusting maximum number of connection tracking entries possible 130 | # 131 | # Conntrack element size 288 bytes found in /proc/slabinfo 132 | # "nf_conntrack" = 288 133 | # 134 | # 288 * 2000000 / 10^6 = 576.0 MB 135 | $su /sbin/sysctl -w net/netfilter/nf_conntrack_max=2000000 136 | 137 | # IMPORTANT: Also adjust hash bucket size for conntracks 138 | # net/netfilter/nf_conntrack_buckets writeable 139 | # via /sys/module/nf_conntrack/parameters/hashsize 140 | # 141 | # Hash entry 8 bytes pointer (uses struct hlist_nulls_head) 142 | # 8 * 2000000 / 10^6 = 16 MB 143 | $su sh -c 'echo 2000000 > /sys/module/nf_conntrack/parameters/hashsize' 144 | 145 | # Hint: Monitor nf_conntrack usage searched, found, new, etc.: 146 | # lnstat -c -1 -f nf_conntrack 147 | 148 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/.gitignore: -------------------------------------------------------------------------------- 1 | compressed-*.txt 2 | decompressed-*.txt 3 | decompressed.txt 4 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/compress-libdeflate.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | https://github.com/SafeteeWoW/LibDeflate 3 | ]]-- 4 | 5 | local deflate = require "LibDeflate" 6 | local input = "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\nWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\nRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\nR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\nsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\nNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\nZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\nAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\nFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\nAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\nOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\ngt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\nPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\nikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\nCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\nlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\navAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\nyJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\nyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\nhCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\nHlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\nMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\nnLRbwHOoq7hHwg==\n-----END CERTIFICATE-----\n\n\n-----BEGIN CERTIFICATE-----\nMIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC\nov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL\nwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D\nLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK\n4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5\nbHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y\nsR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ\nXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4\nFQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc\nSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql\nPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND\nTwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1\nc3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx\n+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB\nATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu\nb3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E\nU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu\nMA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC\n5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW\n9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG\nWCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O\nhe8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC\nDfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n-----END CERTIFICATE-----" 7 | local compress = deflate:CompressDeflate(input) 8 | 9 | file = io.open("decompressed.txt", "w") 10 | io.output(file) 11 | io.write(input) 12 | io.close(file) 13 | 14 | file = io.open("compressed-libdeflate.txt", "w") 15 | io.output(file) 16 | io.write(compress) 17 | io.close(file) 18 | 19 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/compress-lzo.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | https://github.com/starius/luaLZO 3 | ]]-- 4 | 5 | local lzo = require "luaLZO" 6 | local input = "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\nWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\nRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\nR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\nsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\nNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\nZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\nAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\nFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\nAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\nOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\ngt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\nPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\nikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\nCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\nlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\navAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\nyJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\nyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\nhCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\nHlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\nMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\nnLRbwHOoq7hHwg==\n-----END CERTIFICATE-----\n\n\n-----BEGIN CERTIFICATE-----\nMIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC\nov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL\nwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D\nLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK\n4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5\nbHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y\nsR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ\nXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4\nFQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc\nSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql\nPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND\nTwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1\nc3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx\n+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB\nATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu\nb3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E\nU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu\nMA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC\n5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW\n9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG\nWCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O\nhe8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC\nDfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n-----END CERTIFICATE-----" 7 | local compress = lzo.compress(input) 8 | 9 | file = io.open("decompressed.txt", "w") 10 | io.output(file) 11 | io.write(input) 12 | io.close(file) 13 | 14 | file = io.open("compressed-lzo.txt", "w") 15 | io.output(file) 16 | io.write(compress) 17 | io.close(file) 18 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/compress-zlib.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | https://github.com/brimworks/lua-zlib 3 | ]]-- 4 | 5 | local lz = require "zlib" 6 | local input = "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\nWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\nRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\nR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\nsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\nNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\nZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\nAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\nFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\nAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\nOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\ngt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\nPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\nikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\nCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\nlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\navAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\nyJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\nyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\nhCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\nHlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\nMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\nnLRbwHOoq7hHwg==\n-----END CERTIFICATE-----\n\n\n-----BEGIN CERTIFICATE-----\nMIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC\nov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL\nwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D\nLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK\n4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5\nbHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y\nsR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ\nXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4\nFQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc\nSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql\nPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND\nTwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1\nc3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx\n+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB\nATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu\nb3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E\nU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu\nMA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC\n5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW\n9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG\nWCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O\nhe8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC\nDfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n-----END CERTIFICATE-----" 7 | local compress = lz.deflate()(input, "finish") 8 | 9 | file = io.open("decompressed.txt", "w") 10 | io.output(file) 11 | io.write(input) 12 | io.close(file) 13 | 14 | file = io.open("compressed-zlib.txt", "w") 15 | io.output(file) 16 | io.write(compress) 17 | io.close(file) 18 | 19 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/compress-zstd.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | https://github.com/neoxic/lua-zstd 3 | ]]-- 4 | 5 | local zstd = require "zstd" 6 | local input = "-----BEGIN CERTIFICATE-----\nMIIGJDCCBQygAwIBAgISA3dQ5AAmqBmpAMa+zRThwboFMA0GCSqGSIb3DQEBCwUA\nMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD\nEwJSMzAeFw0yMjA5MjkyMjEyMjVaFw0yMjEyMjgyMjEyMjRaMBoxGDAWBgNVBAMT\nD2Nkbi5oYXJvbGRhcy5wdzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB\nAM2RTIXNi5javarK4dxMpTInezcxSbWlojYjUSq4GmT+P27tyUcHqFqXHzEolNRJ\nOvq0fa87lGMb916bYhSfjVKYe9Jk9ThVyGQm/vHZzK6k2alsB/4uwrcDclffDn6h\nZH0viuFmWuMfRMpErHORaKh+XwPB+Bh/do9BnaRJ2kcEZmrVb+TdcnyYNYl3sVF6\nCzKCCmz4ViPomtozZsuK15o/oUBjqGEHTNXgOh2kZsisQTWm9dtbQltYTsfvxjwB\nlfn8awiOtiMc8Cdvkp1FgMwaAOzAHasK+i8HQqFYPDiMO3VBP0s+zmXdE8edeScc\nC6IdtY2nG0jR0NghbQao5RZy6whKD8m32oXiX7PIybFYJsVySc/F0EHoipiHh+1f\ncxw/gskUVDeefrZ7iEuTsj8ch5YZ1wQCPMEslcQmyCkCjde4oQ32XsQgzLtvipZm\nT9JluC2YRZ7JNd9+lYl5X0H7Df9mWBmeNMyXRXTSmVjmUXisBvJEVzjmGqfAsD1S\noyX3c7EyzirB3Wt/gvSe+0j6aqDeIXSzrmE4MVYsL8sDjIctOOU+ZfK+rW79zYg2\nYm0PWAOwvTz3Hpc+Qbr0VZnlbhbemcD2xtUj2XB1aTF3DcF+gsYrF6/CYXV3f5oE\ncpH9ev0I6kq6AZh4xR3Ro8fMumAo4ZFEP6QEQBDNuMcXAgMBAAGjggJKMIICRjAO\nBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFA2K1Rj/c0aZY5t6EEqr3bGOjw4uMB8GA1Ud\nIwQYMBaAFBQusxe3WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggr\nBgEFBQcwAYYVaHR0cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRw\nOi8vcjMuaS5sZW5jci5vcmcvMBoGA1UdEQQTMBGCD2Nkbi5oYXJvbGRhcy5wdzBM\nBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIB\nFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUE\ngfIA8AB1AEalVet1+pEgMLWiiWn0830RLEF0vv1JuIWr8vxw/m1HAAABg4uFz2cA\nAAQDAEYwRAIgPIdgVKKnmDeZL4VxIH/wGkFyIK7l6WmA9TXTJmcyrN4CIC8vBTX9\nEIK/xC5WBA4HQaJgkmGIj8rYXIj3LnQFvk+4AHcA36Veq2iCTx9sre64X04+WurN\nohKkal6OOxLAIERcKnMAAAGDi4XRFQAABAMASDBGAiEAiRoHxyvHdYqhftdOw/4U\nwD+sTOl5vUzOyRPG4lik7IcCIQCp9DjCdQvcTlLxfjcjTPKWiGAQv1sr3ysgC2Ze\npJxtkjANBgkqhkiG9w0BAQsFAAOCAQEAG6hD7Q/o7z4DF4THGoNkX7X9BpKeqeeE\n/NVKv6wY6mDm3vblVqEWPvf1aIXrX/E+v1K/JhmqNG2C1O2hpVzYVYbocmQkyyTy\n8rW3KATMgL64kI1ThEtQ8YPZRQhH0/IkyGzgF6DmDDCxR2WN2jV3tCcT2UIxgqlx\nQrx+ba6Q6SXzp7I2V0Gg3AARIbMzGsmr1KNE2mrVeqCJQvMcBPQHZSJYP2RHP9wV\nfsJl4OngmPzMHIP4KADzLWxZYEVmf1xaMGPiaEofDbebHPNhaKxj6b54Y0PJu9Uc\nJCYuJhrFKrHSmsn1owhUaOwWV4JsPqNzuDuk8MfeBFLoay7qVtTMBA==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\nWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\nRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\nR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\nsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\nNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\nZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\nAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\nFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\nAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\nOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\ngt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\nPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\nikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\nCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\nlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\navAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\nyJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\nyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\nhCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\nHlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\nMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\nnLRbwHOoq7hHwg==\n-----END CERTIFICATE-----\n\n\n-----BEGIN CERTIFICATE-----\nMIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC\nov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL\nwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D\nLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK\n4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5\nbHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y\nsR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ\nXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4\nFQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc\nSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql\nPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND\nTwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1\nc3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx\n+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB\nATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu\nb3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E\nU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu\nMA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC\n5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW\n9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG\nWCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O\nhe8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC\nDfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n-----END CERTIFICATE-----" 7 | local compress = zstd.compress(input) 8 | 9 | file = io.open("decompressed.txt", "w") 10 | io.output(file) 11 | io.write(input) 12 | io.close(file) 13 | 14 | file = io.open("compressed-zstd.txt", "w") 15 | io.output(file) 16 | io.write(compress) 17 | io.close(file) 18 | 19 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/compress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LUA=lua5.1 4 | 5 | for script in $(ls compress-*.lua) 6 | do 7 | perf stat -d $LUA $script 8 | done 9 | 10 | stat -c '%n - %s' compressed-*.txt 11 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/decompress-libdeflate.lua: -------------------------------------------------------------------------------- 1 | local deflate = require "LibDeflate" 2 | 3 | local file_i = io.open("compressed-libdeflate.txt", "r") 4 | local file_o = io.open("decompressed-libdeflate.txt", "w") 5 | io.input(file_i) 6 | io.output(file_o) 7 | local input = file_i:read("*all") 8 | local output = deflate:DecompressDeflate(input) 9 | io.write(output) 10 | io.close(file_i) 11 | io.close(file_o) 12 | 13 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/decompress-lzo.lua: -------------------------------------------------------------------------------- 1 | local lzo = require "luaLZO" 2 | 3 | local file_i = io.open("compressed-lzo.txt", "r") 4 | local file_o = io.open("decompressed-lzo.txt", "w") 5 | io.input(file_i) 6 | io.output(file_o) 7 | local input = file_i:read("*all") 8 | local output = lzo.decompress(input) 9 | io.write(output) 10 | io.close(file_i) 11 | io.close(file_o) 12 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/decompress-zlib.lua: -------------------------------------------------------------------------------- 1 | local lz = require "zlib" 2 | 3 | function decompress(input) 4 | return lz.inflate()(input, "finish") 5 | end 6 | 7 | local file_i = io.open("compressed-zlib.txt", "r") 8 | local file_o = io.open("decompressed-zlib.txt", "w") 9 | io.input(file_i) 10 | io.output(file_o) 11 | local input = file_i:read("*all") 12 | local ok, output = pcall(decompress, input) 13 | if not ok then 14 | print(intput) 15 | return 16 | else 17 | print(output) 18 | end 19 | io.write(output) 20 | io.close(file_i) 21 | io.close(file_o) 22 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/decompress-zstd.lua: -------------------------------------------------------------------------------- 1 | local zstd = require "zstd" 2 | 3 | local file_i = io.open("compressed-zstd.txt", "r") 4 | local file_o = io.open("decompressed-zstd.txt", "w") 5 | io.input(file_i) 6 | io.output(file_o) 7 | local input = file_i:read("*all") 8 | local output = zstd.decompress(input) 9 | io.write(output) 10 | io.close(file_i) 11 | io.close(file_o) 12 | 13 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/decompress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LUA=lua5.1 4 | 5 | for script in $(ls decompress-*.lua) 6 | do 7 | perf stat -d $LUA $script 8 | done 9 | 10 | stat -c '%n - %s' decompressed-*.txt 11 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/.gitignore: -------------------------------------------------------------------------------- 1 | tools 2 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ton31337/tools 2 | 3 | go 1.21.1 4 | 5 | require github.com/cyberdelia/lzo v1.0.0 6 | 7 | require github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e // indirect 8 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cyberdelia/lzo v1.0.0 h1:smmvcahczwI/VWSzZ7iikt50lubari5py3qL4hAEHII= 2 | github.com/cyberdelia/lzo v1.0.0/go.mod h1:UVNk6eM6Sozt1wx17TECJKuqmIY58TJOVeJxjlGGAGs= 3 | github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs= 4 | github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M= 5 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/input.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE-----\nMIIGJDCCBQygAwIBAgISA3dQ5AAmqBmpAMa+zRThwboFMA0GCSqGSIb3DQEBCwUA\nMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD\nEwJSMzAeFw0yMjA5MjkyMjEyMjVaFw0yMjEyMjgyMjEyMjRaMBoxGDAWBgNVBAMT\nD2Nkbi5oYXJvbGRhcy5wdzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB\nAM2RTIXNi5javarK4dxMpTInezcxSbWlojYjUSq4GmT+P27tyUcHqFqXHzEolNRJ\nOvq0fa87lGMb916bYhSfjVKYe9Jk9ThVyGQm/vHZzK6k2alsB/4uwrcDclffDn6h\nZH0viuFmWuMfRMpErHORaKh+XwPB+Bh/do9BnaRJ2kcEZmrVb+TdcnyYNYl3sVF6\nCzKCCmz4ViPomtozZsuK15o/oUBjqGEHTNXgOh2kZsisQTWm9dtbQltYTsfvxjwB\nlfn8awiOtiMc8Cdvkp1FgMwaAOzAHasK+i8HQqFYPDiMO3VBP0s+zmXdE8edeScc\nC6IdtY2nG0jR0NghbQao5RZy6whKD8m32oXiX7PIybFYJsVySc/F0EHoipiHh+1f\ncxw/gskUVDeefrZ7iEuTsj8ch5YZ1wQCPMEslcQmyCkCjde4oQ32XsQgzLtvipZm\nT9JluC2YRZ7JNd9+lYl5X0H7Df9mWBmeNMyXRXTSmVjmUXisBvJEVzjmGqfAsD1S\noyX3c7EyzirB3Wt/gvSe+0j6aqDeIXSzrmE4MVYsL8sDjIctOOU+ZfK+rW79zYg2\nYm0PWAOwvTz3Hpc+Qbr0VZnlbhbemcD2xtUj2XB1aTF3DcF+gsYrF6/CYXV3f5oE\ncpH9ev0I6kq6AZh4xR3Ro8fMumAo4ZFEP6QEQBDNuMcXAgMBAAGjggJKMIICRjAO\nBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFA2K1Rj/c0aZY5t6EEqr3bGOjw4uMB8GA1Ud\nIwQYMBaAFBQusxe3WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggr\nBgEFBQcwAYYVaHR0cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRw\nOi8vcjMuaS5sZW5jci5vcmcvMBoGA1UdEQQTMBGCD2Nkbi5oYXJvbGRhcy5wdzBM\nBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIB\nFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUE\ngfIA8AB1AEalVet1+pEgMLWiiWn0830RLEF0vv1JuIWr8vxw/m1HAAABg4uFz2cA\nAAQDAEYwRAIgPIdgVKKnmDeZL4VxIH/wGkFyIK7l6WmA9TXTJmcyrN4CIC8vBTX9\nEIK/xC5WBA4HQaJgkmGIj8rYXIj3LnQFvk+4AHcA36Veq2iCTx9sre64X04+WurN\nohKkal6OOxLAIERcKnMAAAGDi4XRFQAABAMASDBGAiEAiRoHxyvHdYqhftdOw/4U\nwD+sTOl5vUzOyRPG4lik7IcCIQCp9DjCdQvcTlLxfjcjTPKWiGAQv1sr3ysgC2Ze\npJxtkjANBgkqhkiG9w0BAQsFAAOCAQEAG6hD7Q/o7z4DF4THGoNkX7X9BpKeqeeE\n/NVKv6wY6mDm3vblVqEWPvf1aIXrX/E+v1K/JhmqNG2C1O2hpVzYVYbocmQkyyTy\n8rW3KATMgL64kI1ThEtQ8YPZRQhH0/IkyGzgF6DmDDCxR2WN2jV3tCcT2UIxgqlx\nQrx+ba6Q6SXzp7I2V0Gg3AARIbMzGsmr1KNE2mrVeqCJQvMcBPQHZSJYP2RHP9wV\nfsJl4OngmPzMHIP4KADzLWxZYEVmf1xaMGPiaEofDbebHPNhaKxj6b54Y0PJu9Uc\nJCYuJhrFKrHSmsn1owhUaOwWV4JsPqNzuDuk8MfeBFLoay7qVtTMBA==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\nWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\nRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\nR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\nsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\nNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\nZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\nAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\nFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\nAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\nOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\ngt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\nPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\nikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\nCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\nlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\navAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\nyJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\nyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\nhCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\nHlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\nMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\nnLRbwHOoq7hHwg==\n-----END CERTIFICATE-----\n\n\n-----BEGIN CERTIFICATE-----\nMIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC\nov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL\nwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D\nLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK\n4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5\nbHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y\nsR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ\nXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4\nFQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc\nSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql\nPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND\nTwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1\nc3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx\n+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB\nATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu\nb3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E\nU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu\nMA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC\n5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW\n9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG\nWCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O\nhe8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC\nDfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n-----END CERTIFICATE----- 2 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "compress/zlib" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/cyberdelia/lzo" 10 | ) 11 | 12 | func main() { 13 | data, err := os.ReadFile("input.txt") 14 | if err != nil { 15 | fmt.Printf("can't read input file: %s\n", err) 16 | return 17 | } 18 | 19 | // lzo 20 | 21 | buflzo := new(bytes.Buffer) 22 | 23 | wlzo, err := lzo.NewWriterLevel(buflzo, lzo.BestCompression) 24 | if err != nil { 25 | fmt.Printf("lzo new writer: %s\n", err) 26 | return 27 | } 28 | 29 | if _, err := wlzo.Write(data); err != nil { 30 | fmt.Printf("lzo compress: %s\n", err) 31 | return 32 | } 33 | 34 | wlzo.Close() 35 | 36 | err = os.WriteFile("output-lzo.txt", buflzo.Bytes(), 0644) 37 | if err != nil { 38 | fmt.Printf("lzo write: %s\n", err) 39 | return 40 | } 41 | 42 | // zlib 43 | 44 | bufzlib := new(bytes.Buffer) 45 | 46 | wzlib, err := zlib.NewWriterLevel(bufzlib, zlib.BestCompression) 47 | if err != nil { 48 | fmt.Printf("zlib new writer: %s\n", err) 49 | return 50 | } 51 | 52 | if _, err := wzlib.Write(data); err != nil { 53 | fmt.Printf("zlib compress: %s\n", err) 54 | return 55 | } 56 | 57 | wzlib.Close() 58 | 59 | err = os.WriteFile("output-zlib.txt", bufzlib.Bytes(), 0644) 60 | if err != nil { 61 | fmt.Printf("zlib write: %s\n", err) 62 | return 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/output-lzo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/lua-compress-decompress-performance/go-lzo/output-lzo.txt -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/output-zlib.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/lua-compress-decompress-performance/go-lzo/output-zlib.txt -------------------------------------------------------------------------------- /lua-compress-decompress-performance/go-lzo/tools: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/lua-compress-decompress-performance/go-lzo/tools -------------------------------------------------------------------------------- /memcached_timeout.stp: -------------------------------------------------------------------------------- 1 | # twemproxy keeps persistent connections after restart 2 | # socket_count = (server_connections * number_of_backend_servers) 3 | # need to check how much time (ms) takes connect() when timeouts 4 | 5 | global count; 6 | 7 | probe syscall.connect 8 | { 9 | port = _struct_sockaddr_u_tcp_port($uservaddr, $addrlen); 10 | ip = _struct_sockaddr_u_ip_addr($uservaddr, $addrlen); 11 | if(port == "1101") { 12 | count[ip] = gettimeofday_ms(); 13 | } 14 | } 15 | 16 | probe syscall.connect.return 17 | { 18 | ip = _struct_sockaddr_u_ip_addr($uservaddr, $addrlen); 19 | if(count[ip]) { 20 | delta = gettimeofday_ms() - count[ip]; 21 | if(delta) 22 | printf("%s: %dms\n", ip, delta); 23 | } 24 | } 25 | 26 | probe timer.s(60) { delete count; } 27 | probe end { delete count; } 28 | -------------------------------------------------------------------------------- /memcached_tools.rb: -------------------------------------------------------------------------------- 1 | server_list = [] 2 | 3 | # get server list 4 | File.open('/etc/nutcracker.yml').each_line do |line| 5 | x = /- (.+):(\d+):(\d+)$/.match(line) 6 | server_list << "#{x[1]}:#{x[2]}" unless x.nil? 7 | end 8 | server_list.uniq! 9 | 10 | # iterate over every server and print if slab is full 11 | server_list.each { |srv| 12 | print "#{srv}\n" 13 | print " # Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM\n" 14 | `memcached-tool #{srv}`.each_line do |line| 15 | print line if line.include?('yes') 16 | end 17 | } 18 | 19 | -------------------------------------------------------------------------------- /memcachedlog.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | memcachelog.lua - show most used memcached keys. 3 | 4 | USAGE: sysdig -c memcachelog 5 | eg, 6 | 7 | sysdig -c memcachelog # show memcached get/set utilization 8 | sysdig -c memcachelog get # show memcached only get utilization 9 | sysdig -c memcachelog set # show memcached only set utilization 10 | sysdig -c memcachelog 'set 1000' # show memcached set utilization which object's size is higher than 1000 11 | 12 | By default it will print both methods. 13 | 14 | Copyright (C) 2015 Donatas Abraitis. 15 | 16 | This program is free software: you can redistribute it and/or modify 17 | it under the terms of the GNU General Public License version 2 as 18 | published by the Free Software Foundation. 19 | 20 | This program is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | You should have received a copy of the GNU General Public License 26 | along with this program. If not, see . 27 | --]] 28 | 29 | -- Chisel description 30 | description = "memcached keys utilization" 31 | short_description = "memcached keys utilization" 32 | category = "misc" 33 | 34 | -- Chisel argument list 35 | args = 36 | { 37 | { 38 | name = "method", 39 | description = "get/set", 40 | optional = true 41 | }, 42 | { 43 | name = "size", 44 | description = "object size", 45 | optional = true 46 | } 47 | } 48 | 49 | -- Helpers -- 50 | function split(s, delimiter) 51 | result = {}; 52 | for match in (s..delimiter):gmatch("(.-)"..delimiter) do 53 | table.insert(result, match); 54 | end 55 | return result; 56 | end 57 | 58 | -- Argument notification callback 59 | function on_set_arg(name, val) 60 | if name == "method" then 61 | opt_method = val 62 | return true 63 | elseif name == "size" then 64 | opt_size = tonumber(val) 65 | return true 66 | end 67 | return false 68 | end 69 | 70 | -- Initialization callback 71 | function on_init() 72 | util = {} 73 | start_time = os.time() 74 | sysdig.set_filter("proc.name=memcached and evt.type=read") 75 | sysdig.set_snaplen(4096) 76 | data = chisel.request_field("evt.arg[1]") 77 | datetime = chisel.request_field("evt.datetime") 78 | return true 79 | end 80 | 81 | -- Event callback 82 | function on_event() 83 | local data = evt.field(data) 84 | local line = split(data, " ") 85 | if string.match(line[1], '^[gs]et') ~= nil then 86 | local method = line[1] 87 | local key = line[2] 88 | local size = tonumber(line[5]) or 0 89 | if key ~= nil then 90 | if opt_method ~= nil and opt_method ~= method then 91 | return true 92 | end 93 | if opt_method == 'set' and size < opt_size then 94 | return true 95 | end 96 | print(string.format("%s method=%s size=%dB key=%s", 97 | evt.field(datetime), 98 | method, 99 | size, 100 | key 101 | )) 102 | end 103 | end 104 | return true 105 | end 106 | -------------------------------------------------------------------------------- /memcachedtop.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | memcachetop.lua - show most used memcached keys. 3 | 4 | USAGE: sysdig -c memcachetop 5 | eg, 6 | 7 | sysdig -c memcachetop # show memcached utilization every second and stop after 10 seconds 8 | sysdig -c 5 # show memcached utilization every 5 second and stop after 10 seconds 9 | sysdig -c '2 20' # show memcached utilization every 2 second and stpo after 20 seconds 10 | 11 | By default it will run as sysdig -c '1 10'. 12 | 13 | Copyright (C) 2015 Donatas Abraitis. 14 | 15 | This program is free software: you can redistribute it and/or modify 16 | it under the terms of the GNU General Public License version 2 as 17 | published by the Free Software Foundation. 18 | 19 | This program is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License 25 | along with this program. If not, see . 26 | --]] 27 | 28 | -- Chisel description 29 | description = "memcached keys utilization" 30 | short_description = "memcached keys utilization" 31 | category = "misc" 32 | 33 | -- Chisel argument list 34 | args = 35 | { 36 | { 37 | name = "refresh", 38 | description = "refresh interval", 39 | optional = true 40 | }, 41 | { 42 | name = "stop", 43 | description = "stop tracing after N seconds", 44 | optional = true 45 | }, 46 | } 47 | 48 | -- Helpers -- 49 | terminal = require "ansiterminal" 50 | 51 | function split(s, delimiter) 52 | result = {}; 53 | for match in (s..delimiter):gmatch("(.-)"..delimiter) do 54 | table.insert(result, match); 55 | end 56 | return result; 57 | end 58 | 59 | function sort(t) 60 | local tmp = {} 61 | for key, val in pairs(t) do 62 | table.insert(tmp, val) 63 | end 64 | table.sort(tmp, function(a, b) return a stop_after then sysdig.end_capture() end 119 | local sum = {} 120 | local bytes = {} 121 | local i = 0 122 | for key,v in pairs(util) do 123 | local list = v 124 | sum[key] = 0 125 | bytes[key] = 0 126 | while list do 127 | sum[key] = sum[key] + 1 128 | bytes[key] = list.bytes 129 | list = list.next 130 | end 131 | end 132 | 133 | local res = results(sort(sum), sum) 134 | for key, count in pairs(res) do 135 | local bytes = bytes[key] or 'get' 136 | print(count.."\t\t"..bytes.."\t\t"..key) 137 | end 138 | 139 | util = {} 140 | return true 141 | end 142 | 143 | -- Event callback 144 | function on_event() 145 | local data = evt.field(data) 146 | local line = split(data, " ") 147 | if string.match(line[1], '^[gs]et') ~= nil then 148 | local key = line[2] 149 | local bytes = line[5] 150 | if key ~= nil then 151 | util[key] = { next = util[key], bytes = bytes } 152 | end 153 | end 154 | return true 155 | end 156 | -------------------------------------------------------------------------------- /meminfo.rb: -------------------------------------------------------------------------------- 1 | # print socket memory stats in addition to /proc/meminfo 2 | # ruby meminfo.rb 3 | # @ton31337 4 | 5 | x = [] 6 | ss_output = [] 7 | keys = ['Socket_rmem_alloc', 'Socket_wmem_queued', 'Socket_forward_alloc', \ 8 | 'Socket_wmem_alloc', 'Socket_rcv_space'] 9 | 10 | meminfo = File.read('/proc/meminfo') 11 | 12 | `/usr/sbin/ss -meipn`.each_line do |line| 13 | next if not line.start_with?("\t") 14 | 15 | data = line.match(/mem:\(r(\d+),w(\d+),f(\d+),t(\d+)\).+rcv_space:(\d+)/) 16 | x << data[1..(data.length-1)].map(&:to_i) 17 | end 18 | 19 | data = x.transpose.map { |j| j.reduce(:+) } 20 | 21 | print meminfo 22 | data.each_with_index { |count,i| 23 | printf "%s:\t%s kB\n", keys[i], count/1024 24 | } 25 | 26 | -------------------------------------------------------------------------------- /mmhistogram: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | import argparse 3 | import itertools 4 | import math 5 | import sys 6 | 7 | parser = argparse.ArgumentParser(description='Print log-2 histogram, like systemtap') 8 | parser.add_argument('-t', '--title', default="Values", 9 | help='title to print') 10 | parser.add_argument('-c', '--columns', type=int, default="50", 11 | help='number of colums for') 12 | parser.add_argument('-b', '--base', type=int, default="2", 13 | help='log base') 14 | parser.add_argument('-l', '--linear', action='store_true', 15 | help='do linear, not log') 16 | parser.add_argument('-j', '--justval', action='store_true', 17 | help='ignore bounds, use values from input') 18 | parser.add_argument('-p', '--percentage', action='store_true', 19 | help='Print percentage instead of counts') 20 | args = parser.parse_args() 21 | 22 | 23 | M = [] 24 | for line in sys.stdin: 25 | line = line.strip() 26 | v = float(line) 27 | M.append( v ) 28 | 29 | M.sort(reverse=True) 30 | 31 | totalcount = len(M) 32 | minval = M[-1] 33 | maxval = M[0] 34 | avgval = sum(M) / float(len(M)) 35 | devval = math.sqrt(sum([(m - avgval)**2 for m in M]) / float(len(M))) 36 | 37 | medval = M[len(M)/2] 38 | 39 | KV = [] 40 | 41 | for i in itertools.count(): 42 | if args.justval: 43 | bound=M[-1] 44 | boundb=M[-1] 45 | elif not args.linear: 46 | if i > 0: 47 | boundb = args.base**(i-1) 48 | else: 49 | boundb = 0 50 | bound = args.base**i 51 | else: 52 | boundb = args.base*(i) 53 | bound = args.base*(i+1) 54 | 55 | c = 0 56 | while len(M) > 0 and bound >= M[-1] : 57 | c += 1 58 | M.pop() 59 | KV.append( (boundb, bound, c) ) 60 | 61 | if not M: 62 | break 63 | 64 | maxcount = float(max(c for _, _, c in KV)) 65 | maxbound = KV[-1][0] 66 | boundl = max(len(str(maxbound)), len('value')) 67 | 68 | print "%s min:%.2f avg:%.2f med=%.2f max:%.2f dev:%.2f count:%d" % ( 69 | args.title, 70 | minval, 71 | avgval, 72 | medval, 73 | maxval, 74 | devval, 75 | totalcount, 76 | ) 77 | print "%s:" % ( 78 | args.title, 79 | ) 80 | print "%*s |%*s %s" % ( 81 | boundl+1, 82 | "value", 83 | args.columns, 84 | "-" * args.columns, 85 | "count" 86 | ) 87 | 88 | for boundb, bound, c in KV: 89 | if args.percentage: 90 | cp = "%5.2f%%" % ((c / float(totalcount))*100.0,) 91 | else: 92 | cp = "%d" % (c,) 93 | print "%*d |%*s %s" % ( 94 | boundl + 1, 95 | boundb, 96 | args.columns, 97 | "*" * int(args.columns * (c/maxcount)), 98 | cp 99 | ) 100 | -------------------------------------------------------------------------------- /mpls.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "encoding/hex" 7 | "github.com/google/gopacket" 8 | "github.com/google/gopacket/layers" 9 | ) 10 | 11 | func getMplsPacket() []byte { 12 | 13 | ipaddr := net.ParseIP("1.1.1.1") 14 | 15 | payload := gopacket.Payload("payload") 16 | 17 | udp := &layers.UDP{SrcPort: layers.UDPPort(2000), DstPort: layers.UDPPort(3000)} 18 | 19 | ip := &layers.IPv4{Version: 4, DstIP: ipaddr, SrcIP: ipaddr, Protocol: layers.IPProtocolUDP} 20 | 21 | hw, _ := net.ParseMAC("c8:b3:02:c0:b9:1b") 22 | 23 | eth := &layers.Ethernet{SrcMAC: hw, DstMAC: hw, EthernetType: 0x8847} 24 | 25 | mpls := &layers.MPLS{ 26 | Label: 17, 27 | TrafficClass: 0, 28 | StackBottom: true, 29 | TTL: 64, 30 | } 31 | 32 | if err := udp.SetNetworkLayerForChecksum(ip); err != nil { 33 | return nil 34 | } 35 | 36 | buffer := gopacket.NewSerializeBuffer() 37 | if err := gopacket.SerializeLayers(buffer, 38 | gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}, 39 | eth, mpls, ip, udp, payload); err != nil { 40 | return nil 41 | } 42 | 43 | str := hex.EncodeToString(buffer.Bytes()) 44 | fmt.Println(str) 45 | return buffer.Bytes() 46 | } 47 | 48 | 49 | func main() { 50 | fmt.Println(getMplsPacket()) 51 | } 52 | -------------------------------------------------------------------------------- /mysql-trace.stp: -------------------------------------------------------------------------------- 1 | global tablec; 2 | global indexc; 3 | 4 | probe process("/usr/sbin/mysqld").function("row_search_for_mysql") 5 | { 6 | tablec[user_string($prebuilt->table->name)]++; 7 | indexc[user_string($prebuilt->index->name)]++; 8 | } 9 | 10 | probe timer.s(1) 11 | { 12 | foreach(table in tablec- limit 10) { 13 | printf("table %s -> %d\n", table, tablec[table]); 14 | } 15 | foreach(index in indexc- limit 10) { 16 | printf("index %s -> %d\n", index, indexc[index]); 17 | } 18 | exit(); 19 | } 20 | -------------------------------------------------------------------------------- /net_discards.stp: -------------------------------------------------------------------------------- 1 | # try to find the reason of rx_discards 2 | # stap --all-modules net_discards.stp probe_eth=eth1 3 | # @ton31337 4 | 5 | global locations; 6 | global probe_eth="eth0"; 7 | 8 | probe kernel.trace("kfree_skb") { locations[$location] <<< 1; } 9 | probe timer.s(3) 10 | { 11 | system(sprintf("ethtool -S %s | grep rx_discard | awk '{print \"Discarded packets: \"$2}'", probe_eth)); 12 | printf("=========== BEGIN ================\n"); 13 | foreach(l in locations-) { 14 | printf("%s %d packets dropped at %s\n", 15 | ctime(gettimeofday_s()), @count(locations[l]), symname(l)); 16 | 17 | } 18 | printf("=========== END == ================\n"); 19 | 20 | delete locations; 21 | } 22 | -------------------------------------------------------------------------------- /netdev_budget.stp: -------------------------------------------------------------------------------- 1 | # Tested with 3.10.0-327.18.2.el7.x86_64 2 | # Maximum number of packets taken from all interfaces in one polling cycle (NAPI 3 | # poll). In one polling cycle interfaces which are registered to polling are 4 | # probed in a round-robin manner. 5 | 6 | probe kernel.statement("net_rx_action@net/core/dev.c:4464") 7 | { 8 | avail_budget = $budget - $work; 9 | percentile = (avail_budget * 100) / $budget; 10 | 11 | if (percentile < 50 && percentile >= 0) 12 | printf("%d %d\n", cpu(), percentile); 13 | } 14 | -------------------------------------------------------------------------------- /netdev_max_backlog.stp: -------------------------------------------------------------------------------- 1 | # Tested with 3.10.0-327.18.2.el7.x86_64 2 | 3 | %{ 4 | #include 5 | %} 6 | 7 | function get_queue_len:long(cpu:long) 8 | %{ 9 | struct softnet_data *sd; 10 | sd = &per_cpu(softnet_data, STAP_ARG_cpu); 11 | THIS->__retvalue = skb_queue_len(&sd->input_pkt_queue); 12 | %} 13 | 14 | probe kernel.function("enqueue_to_backlog") 15 | { 16 | queue_length = get_queue_len($cpu); 17 | if (queue_length) 18 | printf("cpu: %d, queue: %d\n", $cpu, queue_length); 19 | } 20 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/.gitignore: -------------------------------------------------------------------------------- 1 | bin/spawn.sh.x* 2 | bin/spawn-php-fpm.sh.x* 3 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | shc -f bin/spawn.sh -o bin/spawn 3 | shc -f bin/spawn-php-fpm.sh -o bin/spawn-php-fpm 4 | 5 | .DEFAULT_GOAL := all 6 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/bin/h5g-spawner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from bcc import BPF 4 | import subprocess 5 | import time 6 | import threading 7 | import re 8 | import os 9 | import sys 10 | import signal 11 | import logging 12 | from stat import * 13 | 14 | bcc_prog = """ 15 | #include 16 | #include 17 | #include 18 | 19 | #define SUN_PATH_LEN 108 20 | #define PERMIT_USER_ID 33 /* www-data */ 21 | 22 | BPF_RINGBUF_OUTPUT(events, 1 << 12); 23 | 24 | struct event { 25 | char sun_path[SUN_PATH_LEN]; 26 | u32 uid; 27 | }; 28 | 29 | struct sockaddr_un { 30 | sa_family_t sun_family; 31 | char sun_path[SUN_PATH_LEN]; 32 | }; 33 | 34 | void schedule_spawn(struct pt_regs *ctx, int fd, struct sockaddr *uservaddr, 35 | int addrlen) 36 | { 37 | struct sockaddr_un *sock = NULL; 38 | struct event e = {}; 39 | 40 | if (uservaddr->sa_family != AF_UNIX) 41 | return; 42 | 43 | e.uid = bpf_get_current_uid_gid(); 44 | if (e.uid != PERMIT_USER_ID) 45 | return; 46 | 47 | sock = (struct sockaddr_un *)uservaddr; 48 | 49 | bpf_probe_read_user_str(&e.sun_path, sizeof(e.sun_path), 50 | sock->sun_path); 51 | 52 | events.ringbuf_output(&e, sizeof(e), 0); 53 | } 54 | """ 55 | 56 | b = BPF(text=bcc_prog) 57 | b.attach_kprobe(event="__sys_connect", fn_name="schedule_spawn") 58 | 59 | 60 | class Spawner: 61 | def __init__(self): 62 | logging.basicConfig(format="%(levelname)s: %(message)s", stream=sys.stdout) 63 | 64 | self.bin_dir = "/opt/h5g/bin" 65 | self.run_dir = "/opt/h5g/run" 66 | self.idle_timeout = 30 67 | self.last_seen = {} 68 | self.seen_counter = {} 69 | self.thread_stop_event = threading.Event() 70 | self.log = logging.getLogger(__name__) 71 | self.log.setLevel(logging.DEBUG) 72 | 73 | def socket2username(self, path): 74 | """ 75 | A helper method to validate if we got a valid socket path. 76 | E.g.: u000000002-example.org/php.socket 77 | """ 78 | m = re.search(r"(u[\d\w]{1,9}-.+)\/(php|ssh)\.socket$", path) 79 | if not m: 80 | self.log.error(f"can't parse socket path to username: {path}") 81 | return None 82 | return m[1] 83 | 84 | def pidfile2username(self, path): 85 | """ 86 | A helper method to validate if we got a valid pid path. 87 | E.g.: u000000002-example.org/php.pid 88 | """ 89 | m = re.search(r"(u[\d\w]{1,9})-(.+)\/(php|ssh)\.pid$", path) 90 | if not m: 91 | self.log.error(f"can't parse pidfile path to username: {path}") 92 | return None 93 | return m[1], m[2] 94 | 95 | def terminate(self, pid_file, msg): 96 | """ 97 | Send a termination signal for the pid that belongs to the 98 | php-fpm process we would like to terminate due to idle timeout. 99 | """ 100 | with open(pid_file, "r") as f: 101 | pid = int(f.read()) 102 | if pid > 1: 103 | self.log.info(msg) 104 | try: 105 | os.kill(pid, signal.SIGINT) 106 | except: 107 | pass 108 | 109 | def spawn(self, _cpu, data, _size): 110 | """ 111 | When we receive `connect()`, we run `spawn.sh` command with an 112 | argument, which is in our case a socket's path. 113 | E.g.: `spawn.sh /tmp/u2.socket`. 114 | """ 115 | output = b["events"].event(data) 116 | sun_path = output.sun_path.decode("utf-8") 117 | 118 | if self.run_dir not in sun_path: 119 | return 120 | 121 | if not self.socket2username(sun_path): 122 | return 123 | 124 | if sun_path in self.seen_counter: 125 | self.seen_counter[sun_path] = self.seen_counter[sun_path] + 1 126 | else: 127 | self.seen_counter[sun_path] = 0 128 | 129 | now = int(time.time()) 130 | 131 | # If we receive a burst of connect()s, we should avoid saturating 132 | # ring buffer for user-space/kernel-space communication. 133 | # With this limitation, we send only _legit_ requests down to the user-space, 134 | # and spawn.sh is doing the decent job. 135 | if ( 136 | sun_path in self.last_seen 137 | and now - self.last_seen[sun_path] < self.idle_timeout / 2 138 | ): 139 | return 140 | 141 | self.last_seen[sun_path] = now 142 | 143 | subprocess.Popen( 144 | [os.path.join(self.bin_dir, "spawn.sh"), sun_path], 145 | stdout=subprocess.PIPE, 146 | stderr=subprocess.PIPE, 147 | ) 148 | 149 | def reap_timer(self): 150 | """ 151 | Iterate over the `run_dir` and check the existing/running 152 | php-fpm processes. 153 | If the socket didn't have any request during the idle timeout, 154 | then terminate php-fpm for that specific user. 155 | If php-fpm was running before we started this program, we should 156 | check how it long it was active by evaluating socket's file ATIME. 157 | """ 158 | self.log.debug("Checking idle user processes...") 159 | for f in os.listdir(self.run_dir): 160 | pid_file = f"{self.run_dir}/{f}/php.pid" 161 | try: 162 | s = os.lstat(pid_file) 163 | if not S_ISREG(s.st_mode): 164 | continue 165 | except: 166 | continue 167 | 168 | username, bundle = self.pidfile2username(pid_file) 169 | if not username: 170 | continue 171 | 172 | sun_path = f"{self.run_dir}/{username}-{bundle}/php.socket" 173 | 174 | if ( 175 | sun_path in self.last_seen 176 | and int(time.time() - self.last_seen[sun_path]) > self.idle_timeout 177 | ): 178 | self.terminate( 179 | pid_file, 180 | f"Terminating user process (no requests during idle timeout) for {username}", 181 | ) 182 | 183 | if ( 184 | sun_path not in self.last_seen 185 | and int(time.time() - s.st_atime) > self.idle_timeout 186 | ): 187 | self.terminate( 188 | pid_file, 189 | f"Terminating user process (socket created, but no requests during idle timeout) for {username}", 190 | ) 191 | 192 | def reap(self, func, stop_event): 193 | """ 194 | The process reaping thread, that calls another function periodically. 195 | In our case `reap_timer()`. 196 | """ 197 | 198 | def expired(): 199 | while not stop_event.is_set(): 200 | for _ in range(self.idle_timeout): 201 | if stop_event.is_set(): 202 | break 203 | time.sleep(1) 204 | func() 205 | 206 | thread = threading.Thread(target=expired) 207 | thread.start() 208 | 209 | 210 | if __name__ == "__main__": 211 | h5g = Spawner() 212 | b["events"].open_ring_buffer(h5g.spawn) 213 | h5g.reap(h5g.reap_timer, h5g.thread_stop_event) 214 | h5g.log.info("Running, and waiting for `connect()` events...") 215 | h5g.log.info(f"run path: {h5g.run_dir}") 216 | h5g.log.info(f"bin path: {h5g.bin_dir}") 217 | h5g.log.info(f"idle timeout: {h5g.idle_timeout}") 218 | 219 | while True: 220 | try: 221 | b.ring_buffer_poll() 222 | except KeyboardInterrupt: 223 | h5g.thread_stop_event.set() 224 | h5g.log.debug(h5g.last_seen) 225 | h5g.log.debug(h5g.seen_counter) 226 | exit() 227 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/bin/spawn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/nginx-lua-ebpf-socket-spawn-process/bin/spawn -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/bin/spawn-php-fpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/nginx-lua-ebpf-socket-spawn-process/bin/spawn-php-fpm -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/bin/spawn-php-fpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # $ shc -f spawn-php-fpm.sh -o spawn-php-fpm 3 | # 4 | # Make sure the host has this /proc mount (hidepid=2) 5 | # mount -o remount,hidepid=2 /proc 6 | # 7 | # Another option would be using minijail() (= minijail0): 8 | # sudo /home/donatas/minijail/minijail-linux-v18/minijail0 \ 9 | # -c 0xffffffff --ambient -u www-data -p -i -f /tmp/h5g/u2.jail.pid \ 10 | # -- /usr/sbin/php-fpm8.2 --fpm-config /etc/php-fpm/h5g/u2.conf 11 | # 12 | # Configure cgroups: 13 | #% cat /etc/cgroup.conf 14 | #group www-data { 15 | # cpu { 16 | # cpu.shares = 100; 17 | # cpu.cfs_quota_us = 1000; 18 | # } 19 | # ... 20 | # Do not forget to do `cgconfigparser -l /etc/cgroup.conf` 21 | 22 | set -x 23 | 24 | CHROOT="/var/lib/machines/debian" 25 | 26 | #/bin/mount --bind --make-unbindable /dev/pts/ "${CHROOT}/dev/pts" 27 | #/bin/mount --bind --make-unbindable /opt/h5g/skeleton/etc/passwd "${CHROOT}/etc/passwd" 28 | #/bin/mount --bind --make-unbindable /opt/h5g/skeleton/etc/group "${CHROOT}/etc/group" 29 | #/bin/mount --bind --make-unbindable /opt/h5g/skeleton/etc/php-fpm.conf "${CHROOT}/etc/php-fpm.conf" 30 | #/bin/mount --bind --make-unbindable /var/www/u2 "${CHROOT}/var/www/u2" 31 | #/bin/mount --bind --make-unbindable /tmp "${CHROOT}/tmp" 32 | #/bin/mount --type proc none "${CHROOT}/proc" || \ 33 | # /bin/mount -o remount --type proc none "${CHROOT}/proc" 34 | #/bin/mount -o remount,noexec,nosuid,nodev "${CHROOT}/tmp" 35 | /usr/bin/cgexec -g cpu:www-data \ 36 | /usr/bin/prlimit --nofile=256 --nproc=512 --locks=32 \ 37 | /sbin/capsh --drop=all --user=www-data --chroot="${CHROOT}" -- -c '/usr/sbin/php-fpm8.2 --fpm-config /etc/php-fpm.conf' 38 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/bin/spawn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # $ shc -f spawn.sh -o spawn 3 | 4 | set -x 5 | 6 | # User input comes as /tmp/u12345678.socket. 7 | # Parse some more relevant parts, like u12345678. 8 | US_PATH="${1}" 9 | US_NAME=$(basename "${US_PATH}") 10 | US_USER="${US_NAME::-7}" 11 | 12 | if [[ ${US_PATH} == *".socket"* ]]; then 13 | if ! grep "${US_PATH}" /proc/net/unix; then 14 | /usr/bin/unshare \ 15 | --mount \ 16 | --propagation private \ 17 | /opt/h5g/bin/spawn-php-fpm.sh "${US_USER}" \ 18 | 2>"/tmp/unshare-${US_USER}.log" \ 19 | >"/tmp/unshare-${US_USER}.log" 20 | fi 21 | fi 22 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/etc/h5g.js: -------------------------------------------------------------------------------- 1 | import http from 'k6/http'; 2 | import { sleep, check } from 'k6'; 3 | import { Counter } from 'k6/metrics'; 4 | import { randomString } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; 5 | import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; 6 | import redis from 'k6/experimental/redis'; 7 | 8 | export const requests = new Counter('http_reqs'); 9 | export const options = { 10 | stages: [ 11 | { target: 100, duration: '1m' }, 12 | { target: 200, duration: '1m' }, 13 | { target: 300, duration: '1m' }, 14 | ], 15 | }; 16 | 17 | const redis_addrs = '127.0.0.1:6379'; 18 | const redis_password = ''; 19 | const redisClient = new redis.Client({ 20 | addrs: redis_addrs.split(','), 21 | password: redis_password, 22 | }); 23 | 24 | export default async function () { 25 | const randomPostfixLen = randomIntBetween(1, 3); 26 | const postfix = randomString(randomPostfixLen, '1234567890abcdef') 27 | const domain = 'dainius' + postfix + '.lt'; 28 | const exists = await redisClient.exists('vhost:' + domain); 29 | 30 | if (exists == true) { 31 | const params = { headers: { 'Host': domain } }; 32 | const res = http.get('http://127.0.0.1', params); 33 | sleep(1); 34 | const checkRes = check(res, { 35 | 'status is 200': (r) => r.status === 200, 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/etc/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8082; 3 | 4 | root /var/www; 5 | index index.html index.htm index.nginx-debian.html; 6 | server_name _; 7 | 8 | location / { 9 | try_files $uri $uri/ =404; 10 | } 11 | 12 | location ~ \.php$ { 13 | access_by_lua_block { 14 | local sock = ngx.socket.tcp() 15 | local sleep = 0.05 16 | 17 | while sleep < 5 do 18 | local ok, err = sock:connect("unix:/tmp/u2.socket") 19 | sock:close() 20 | if ok then 21 | break 22 | end 23 | ngx.sleep(sleep) 24 | sleep = sleep + 0.5 25 | end 26 | 27 | } 28 | include snippets/fastcgi-php.conf; 29 | fastcgi_pass unix:/$h5g_socket; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/skeleton/etc/group: -------------------------------------------------------------------------------- 1 | root:x:0: 2 | daemon:x:1: 3 | bin:x:2: 4 | sys:x:3: 5 | adm:x:4: 6 | tty:x:5: 7 | disk:x:6: 8 | lp:x:7: 9 | man:x:12: 10 | kmem:x:15: 11 | dialout:x:20: 12 | sudo:x:27: 13 | dip:x:30: 14 | www-data:x:33: 15 | shadow:x:42: 16 | utmp:x:43: 17 | video:x:44: 18 | mysql:x:153: 19 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/skeleton/etc/passwd: -------------------------------------------------------------------------------- 1 | root:x:0:0:root:/root:/bin/zsh 2 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 3 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 4 | sys:x:3:3:sys:/dev:/usr/sbin/nologin 5 | sync:x:4:65534:sync:/bin:/bin/sync 6 | games:x:5:60:games:/usr/games:/usr/sbin/nologin 7 | man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 8 | lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin 9 | mail:x:8:8:mail:/var/mail:/usr/sbin/nologin 10 | news:x:9:9:news:/var/spool/news:/usr/sbin/nologin 11 | uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin 12 | proxy:x:13:13:proxy:/bin:/usr/sbin/nologin 13 | www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin 14 | nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin 15 | syslog:x:102:106::/home/syslog:/usr/sbin/nologin 16 | mysql:x:140:153:MySQL Server,,,:/nonexistent:/bin/false 17 | -------------------------------------------------------------------------------- /nginx-lua-ebpf-socket-spawn-process/skeleton/etc/php-fpm.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | pid = /tmp/h5g/u2.pid 3 | error_log = /tmp/h5g/u2.log 4 | 5 | [www] 6 | user = www-data 7 | group = www-data 8 | listen = /tmp/h5g/u2.socket 9 | listen.owner = www-data 10 | listen.group = www-data 11 | pm = ondemand 12 | pm.max_children = 4 13 | -------------------------------------------------------------------------------- /ngx_http_lua_socket_tcp_send.stp: -------------------------------------------------------------------------------- 1 | global counter; 2 | 3 | probe process("/usr/local/openresty/nginx/sbin/nginx").function("ngx_http_lua_socket_tcp_send").return 4 | { 5 | x = gettimeofday_us() - @entry(gettimeofday_us()); 6 | counter <<< x; 7 | } 8 | 9 | probe timer.s(1) 10 | { 11 | if (@count(counter)) { 12 | printf("min: %d, max: %d, avg: %d, count: %d\n", @min(counter), @max(counter), @avg(counter), @count(counter)); 13 | delete counter; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /redis-cluster-migrate/README.md: -------------------------------------------------------------------------------- 1 | ### Usage 2 | `redis-cli keys \* | xargs -I {} ruby migrate.rb {} | bash` 3 | 4 | Notice, that `COPY` and `REPLACE` flags are only available since Redis 3.0 5 | -------------------------------------------------------------------------------- /redis-cluster-migrate/crc16.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Salvatore Sanfilippo 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining 4 | # a copy of this software and associated documentation files (the 5 | # "Software"), to deal in the Software without restriction, including 6 | # without limitation the rights to use, copy, modify, merge, publish, 7 | # distribute, sublicense, and/or sell copies of the Software, and to 8 | # permit persons to whom the Software is furnished to do so, subject to 9 | # the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be 12 | # included in all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | # 22 | # ----------------------------------------------------------------------------- 23 | # 24 | # This is the CRC16 algorithm used by Redis Cluster to hash keys. 25 | # Implementation according to CCITT standards. 26 | # 27 | # This is actually the XMODEM CRC 16 algorithm, using the 28 | # following parameters: 29 | # 30 | # Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN" 31 | # Width : 16 bit 32 | # Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1) 33 | # Initialization : 0000 34 | # Reflect Input byte : False 35 | # Reflect Output CRC : False 36 | # Xor constant to output CRC : 0000 37 | # Output for "123456789" : 31C3 38 | 39 | module RedisClusterCRC16 40 | 41 | def RedisClusterCRC16.crc16(bytes) 42 | crc = 0 43 | bytes.each_byte{|b| 44 | crc = ((crc<<8) & 0xffff) ^ XMODEMCRC16Lookup[((crc>>8)^b) & 0xff] 45 | } 46 | crc 47 | end 48 | 49 | private 50 | 51 | XMODEMCRC16Lookup = [ 52 | 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, 53 | 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, 54 | 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, 55 | 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, 56 | 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, 57 | 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, 58 | 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, 59 | 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, 60 | 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, 61 | 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, 62 | 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, 63 | 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, 64 | 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, 65 | 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, 66 | 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, 67 | 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, 68 | 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, 69 | 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, 70 | 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, 71 | 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, 72 | 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, 73 | 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, 74 | 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, 75 | 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, 76 | 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, 77 | 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, 78 | 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, 79 | 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, 80 | 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, 81 | 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, 82 | 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, 83 | 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 84 | ] 85 | end 86 | -------------------------------------------------------------------------------- /redis-cluster-migrate/migrate.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 127.0.0.1:6379> cluster slots 3 | 1) 1) (integer) 5500 4 | 2) (integer) 10928 5 | 3) 1) "172.17.0.20" 6 | 2) (integer) 6380 7 | 4) 1) "172.17.0.19" 8 | 2) (integer) 6379 9 | 2) 1) (integer) 0 10 | 2) (integer) 5499 11 | 3) 1) "172.17.0.20" 12 | 2) (integer) 6379 13 | 4) 1) "172.17.0.19" 14 | 2) (integer) 6380 15 | 3) 1) (integer) 10929 16 | 2) (integer) 16383 17 | 3) 1) "172.17.0.18" 18 | 2) (integer) 6379 19 | =end 20 | 21 | require './crc16' 22 | 23 | slots = 16384 24 | nodes = { 25 | "1172.17.0.20" => { 26 | :range => 0..5499, 27 | :port => 6379 28 | }, 29 | "2172.17.0.20" => { 30 | :range => 5500..10928, 31 | :port => 6380 32 | }, 33 | "3172.17.0.18" => { 34 | :range => 10929..16383, 35 | :port => 6379 36 | } 37 | } 38 | 39 | key = ARGV[0] 40 | slot = RedisClusterCRC16.crc16(key) % slots 41 | 42 | nodes.each { |host,val| 43 | node = host[1..-1] 44 | port = val[:port] 45 | if (val[:range]) === slot 46 | print "redis-cli MIGRATE #{node} #{port} #{key} 0 5000\n" 47 | end 48 | } 49 | -------------------------------------------------------------------------------- /redis-module/.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | --- 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignEscapedNewlines: Right 7 | AlignOperands: Align 8 | AlignTrailingComments: true 9 | AlignConsecutiveMacros: true 10 | AllowAllParametersOfDeclarationOnNextLine: false 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: None 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: false 19 | AlwaysBreakTemplateDeclarations: false 20 | BinPackArguments: true 21 | BinPackParameters: true 22 | BraceWrapping: 23 | AfterClass: false 24 | AfterControlStatement: false 25 | AfterEnum: false 26 | AfterFunction: true 27 | AfterNamespace: true 28 | AfterObjCDeclaration: false 29 | AfterStruct: false 30 | AfterUnion: false 31 | AfterExternBlock: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: false 39 | BreakBeforeBraces: Custom 40 | BreakBeforeInheritanceComma: false 41 | BreakBeforeTernaryOperators: true 42 | BreakConstructorInitializersBeforeComma: false 43 | BreakConstructorInitializers: BeforeComma 44 | BreakAfterJavaFieldAnnotations: false 45 | BreakStringLiterals: false 46 | ColumnLimit: 80 47 | CompactNamespaces: false 48 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 49 | ConstructorInitializerIndentWidth: 8 50 | ContinuationIndentWidth: 8 51 | Cpp11BracedListStyle: false 52 | DerivePointerAlignment: false 53 | DisableFormat: false 54 | ExperimentalAutoDetectBinPacking: false 55 | IncludeBlocks: Preserve 56 | IndentCaseLabels: false 57 | IndentGotoLabels: false 58 | IndentPPDirectives: None 59 | IndentWidth: 8 60 | IndentWrappedFunctionNames: false 61 | JavaScriptQuotes: Leave 62 | JavaScriptWrapImports: true 63 | KeepEmptyLinesAtTheStartOfBlocks: false 64 | MacroBlockBegin: '' 65 | MacroBlockEnd: '' 66 | ## Linux: MaxEmptyLinesToKeep: 1 67 | MaxEmptyLinesToKeep: 2 68 | NamespaceIndentation: None 69 | ObjCBinPackProtocolList: Auto 70 | ObjCBlockIndentWidth: 8 71 | ObjCSpaceAfterProperty: true 72 | ObjCSpaceBeforeProtocolList: true 73 | PenaltyBreakAssignment: 30 74 | PenaltyBreakComment: 10 75 | PenaltyBreakFirstLessLess: 0 76 | PenaltyBreakString: 1000 77 | PenaltyBreakBeforeFirstCallParameter: 1000 78 | PenaltyExcessCharacter: 30 79 | PenaltyReturnTypeOnItsOwnLine: 60 80 | PointerAlignment: Right 81 | ReflowComments: false 82 | SortIncludes: false 83 | SortUsingDeclarations: false 84 | SpaceAfterCStyleCast: false 85 | SpaceAfterTemplateKeyword: true 86 | SpaceBeforeAssignmentOperators: true 87 | SpaceBeforeCtorInitializerColon: true 88 | SpaceBeforeInheritanceColon: true 89 | SpaceBeforeParens: ControlStatements 90 | SpaceBeforeRangeBasedForLoopColon: true 91 | SpaceInEmptyParentheses: false 92 | SpacesBeforeTrailingComments: 1 93 | SpacesInAngles: false 94 | SpacesInContainerLiterals: false 95 | SpacesInCStyleCastParentheses: false 96 | SpacesInParentheses: false 97 | SpacesInSquareBrackets: false 98 | Standard: Cpp03 99 | TabWidth: 8 100 | UseTab: Always 101 | ... 102 | -------------------------------------------------------------------------------- /redis-module/.gitignore: -------------------------------------------------------------------------------- 1 | module.so 2 | module.o 3 | -------------------------------------------------------------------------------- /redis-module/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gcc -fPIC -std=gnu99 -c -o module.o hproxy.c 4 | ld -o module.so module.o -shared -Bsymbolic -lc 5 | cp ./module.so /tmp/module.so 6 | -------------------------------------------------------------------------------- /redis-module/flushdb.c: -------------------------------------------------------------------------------- 1 | #include "redismodule.h" 2 | #include 3 | 4 | void h5g_flushdbCommandFilter(RedisModuleCommandFilterCtx *filter) 5 | { 6 | size_t cmd_len; 7 | 8 | if (RedisModule_CommandFilterArgsCount(filter) > 1) 9 | return; 10 | 11 | RedisModuleString *cmd = RedisModule_CommandFilterArgGet(filter, 0); 12 | const char *cmd_str = RedisModule_StringPtrLen(cmd, &cmd_len); 13 | 14 | if (cmd_len == 7 && !strncasecmp(cmd_str, "flushdb", cmd_len)) { 15 | RedisModule_CommandFilterArgReplace(filter, 0, 16 | RedisModule_CreateString(NULL, 17 | "FCALL", 18 | 5)); 19 | RedisModule_CommandFilterArgInsert(filter, 1, 20 | RedisModule_CreateString(NULL, 21 | "h5g_flushdb", 22 | 11)); 23 | RedisModule_CommandFilterArgInsert(filter, 2, 24 | RedisModule_CreateString(NULL, 25 | "0", 26 | 1)); 27 | } 28 | } 29 | 30 | int RedisModule_OnLoad(RedisModuleCtx *ctx) 31 | { 32 | if (RedisModule_Init(ctx, "h5g", 1, REDISMODULE_APIVER_1) == 33 | REDISMODULE_ERR) 34 | return REDISMODULE_ERR; 35 | 36 | if (RedisModule_RegisterCommandFilter(ctx, h5g_flushdbCommandFilter, 37 | 0) == NULL) 38 | return REDISMODULE_ERR; 39 | 40 | return REDISMODULE_OK; 41 | } 42 | -------------------------------------------------------------------------------- /redis-module/h5g_flushdb.lua: -------------------------------------------------------------------------------- 1 | #!lua name=h5g 2 | 3 | redis.register_function( 4 | 'h5g_flushdb', 5 | function() 6 | local cur = 0 7 | local deleted = 0 8 | local user = redis.call("ACL", "WHOAMI") 9 | local match = user .. ":*" 10 | 11 | repeat 12 | local res = redis.call("SCAN", cur, "MATCH", match) 13 | cur = tonumber(res[1]) 14 | local keys = res[2] 15 | 16 | for _, key in ipairs(keys) do 17 | redis.call("DEL", key) 18 | deleted = deleted + 1 19 | end 20 | until cur == 0 21 | 22 | return deleted 23 | end 24 | ) 25 | -------------------------------------------------------------------------------- /redis-module/hproxy.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2024 Donatas Abraitis 4 | */ 5 | 6 | #include "redismodule.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define NUM_REDIS_DATABASES 8192 13 | #define SCAN "scan" 14 | #define FLUSHDB "flushdb" 15 | 16 | void strsplit(const char *string, const char *delimiter, char ***result, 17 | int *argc) 18 | { 19 | if (!string) 20 | return; 21 | 22 | unsigned int sz = 4, idx = 0; 23 | char *copy, *copystart; 24 | const char *tok = NULL; 25 | 26 | *result = calloc(sizeof(char *) * sz, 1); 27 | copystart = copy = strdup(string); 28 | *argc = 0; 29 | 30 | while (copy) { 31 | tok = strsep(©, delimiter); 32 | (*result)[idx] = strdup(tok); 33 | if (++idx == sz) 34 | *result = realloc(*result, (sz *= 2) * sizeof(char *)); 35 | (*argc)++; 36 | } 37 | 38 | free(copystart); 39 | } 40 | 41 | const char *cmd_real_get(const char *cmd) 42 | { 43 | int num_splits; 44 | char **splits; 45 | static char command[BUFSIZ] = {}; 46 | 47 | strsplit(cmd, ".", &splits, &num_splits); 48 | 49 | if (num_splits < 2) 50 | return cmd; 51 | 52 | strncpy(command, splits[1], sizeof(command)); 53 | 54 | for (unsigned int i = 0; i < num_splits; i++) 55 | free(splits[i]); 56 | 57 | free(splits); 58 | 59 | return command; 60 | } 61 | 62 | const char *cmd_proxy_get(const char *cmd) 63 | { 64 | static char command[BUFSIZ] = {}; 65 | 66 | snprintf(command, sizeof(command), "hproxy.%s", cmd); 67 | 68 | return command; 69 | } 70 | 71 | uint32_t crc32(const char *key) 72 | { 73 | uint32_t crc = 0xffffffff; 74 | 75 | for (int i = 0; key[i] != '\0'; ++i) { 76 | crc ^= (uint8_t)key[i]; 77 | for (int j = 0; j < 8; ++j) { 78 | crc = (crc >> 1) ^ (0xEDB88320 & (-(crc & 1))); 79 | } 80 | } 81 | 82 | return ~crc; 83 | } 84 | 85 | int HProxyCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) 86 | { 87 | RedisModuleCallReply *reply; 88 | 89 | if (argc < 1) 90 | return RedisModule_WrongArity(ctx); 91 | 92 | const char *cmd = cmd_real_get(RedisModule_StringPtrLen(argv[0], NULL)); 93 | const char *account = 94 | RedisModule_StringPtrLen(RedisModule_GetCurrentUserName(ctx), 95 | NULL); 96 | 97 | /* If the account is default (= admin), don't force DB */ 98 | if (strncmp(account, "default", strlen("default"))) 99 | RedisModule_SelectDb(ctx, crc32(account) % NUM_REDIS_DATABASES); 100 | 101 | if (!strncmp(cmd, SCAN, strlen(SCAN)) && argc > 1) { 102 | unsigned long long arg1; 103 | 104 | if (RedisModule_StringToULongLong(argv[1], &arg1) != 105 | REDISMODULE_OK) 106 | RedisModule_ReplyWithSimpleString(ctx, "ERR"); 107 | 108 | reply = RedisModule_Call(ctx, cmd, "l", arg1); 109 | } else if (cmd, FLUSHDB, strlen(FLUSHDB)) { 110 | reply = RedisModule_Call(ctx, cmd, "v", argv, 0); 111 | } 112 | 113 | if (reply) { 114 | RedisModule_ReplyWithCallReply(ctx, reply); 115 | RedisModule_FreeCallReply(reply); 116 | } else 117 | RedisModule_ReplyWithLongLong(ctx, 0); 118 | 119 | return REDISMODULE_OK; 120 | } 121 | 122 | void HProxyCommandFilter(RedisModuleCommandFilterCtx *filter) 123 | { 124 | size_t cmd_len; 125 | 126 | const char *cmd_real = 127 | RedisModule_StringPtrLen(RedisModule_CommandFilterArgGet(filter, 128 | 0), 129 | &cmd_len); 130 | 131 | if (strncmp(cmd_real, SCAN, strlen(SCAN)) && 132 | strncmp(cmd_real, FLUSHDB, strlen(FLUSHDB))) 133 | return; 134 | 135 | const char *cmd_proxy = cmd_proxy_get(cmd_real); 136 | 137 | RedisModule_CommandFilterArgReplace( 138 | filter, 0, 139 | RedisModule_CreateString(NULL, cmd_proxy, strlen(cmd_proxy))); 140 | } 141 | 142 | int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) 143 | { 144 | if (RedisModule_Init(ctx, "h5g", 1, REDISMODULE_APIVER_1) == 145 | REDISMODULE_ERR) 146 | return REDISMODULE_ERR; 147 | 148 | if (RedisModule_CreateCommand(ctx, cmd_proxy_get(SCAN), HProxyCommand, 149 | "", 1, 1, 1) == REDISMODULE_ERR) 150 | return REDISMODULE_ERR; 151 | 152 | if (RedisModule_CreateCommand(ctx, cmd_proxy_get(FLUSHDB), HProxyCommand, 153 | "", 1, 1, 1) == REDISMODULE_ERR) 154 | return REDISMODULE_ERR; 155 | 156 | if (RedisModule_RegisterCommandFilter(ctx, HProxyCommandFilter, 157 | REDISMODULE_CMDFILTER_NOSELF) == 158 | NULL) 159 | return REDISMODULE_ERR; 160 | 161 | return REDISMODULE_OK; 162 | } 163 | -------------------------------------------------------------------------------- /redis-module/hproxy.flushdb.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2024 Donatas Abraitis 4 | */ 5 | 6 | #include "redismodule.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define NUM_REDIS_DATABASES 32768 13 | const char *flushdb_str = "flushdb"; 14 | const char *hproxy_flushdb_str = "hproxy.flushdb"; 15 | 16 | uint32_t crc32(const char *key) 17 | { 18 | uint32_t crc = 0xffffffff; 19 | for (int i = 0; key[i] != '\0'; ++i) { 20 | crc ^= (uint8_t)key[i]; 21 | for (int j = 0; j < 8; ++j) { 22 | crc = (crc >> 1) ^ (0xEDB88320 & (-(crc & 1))); 23 | } 24 | } 25 | return ~crc; 26 | } 27 | 28 | int HProxyFlushDB(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) 29 | { 30 | uint16_t db_id; 31 | RedisModuleCallReply *reply; 32 | RedisModuleString *new_argv[2]; 33 | int new_argc; 34 | 35 | if (argc != 2) 36 | return RedisModule_WrongArity(ctx); 37 | 38 | const char *cmd = RedisModule_StringPtrLen(argv[0], NULL); 39 | const char *account = 40 | RedisModule_StringPtrLen(RedisModule_GetCurrentUserName(ctx), 41 | NULL); 42 | 43 | if (!strncasecmp(cmd, hproxy_flushdb_str, strlen(hproxy_flushdb_str))) { 44 | db_id = crc32(account) % NUM_REDIS_DATABASES; 45 | RedisModule_SelectDb(ctx, db_id); 46 | } 47 | 48 | new_argv[0] = RedisModule_CreateString(NULL, flushdb_str, 49 | strlen(flushdb_str)); 50 | new_argv[1] = NULL; 51 | 52 | reply = RedisModule_Call(ctx, flushdb_str, "v", new_argv, 0); 53 | if (reply) { 54 | RedisModule_ReplyWithCallReply(ctx, reply); 55 | RedisModule_FreeCallReply(reply); 56 | } else 57 | RedisModule_ReplyWithLongLong(ctx, 0); 58 | 59 | return REDISMODULE_OK; 60 | } 61 | 62 | void ProxyCommandFilter(RedisModuleCommandFilterCtx *filter) 63 | { 64 | size_t cmd_len; 65 | 66 | RedisModuleString *cmd = RedisModule_CommandFilterArgGet(filter, 0); 67 | const char *cmd_str = RedisModule_StringPtrLen(cmd, &cmd_len); 68 | 69 | if (!strncasecmp(cmd_str, flushdb_str, strlen(flushdb_str))) { 70 | RedisModule_CommandFilterArgReplace( 71 | filter, 0, 72 | RedisModule_CreateString(NULL, hproxy_flushdb_str, 73 | strlen(hproxy_flushdb_str))); 74 | RedisModule_CommandFilterArgInsert(filter, 1, cmd); 75 | } 76 | } 77 | 78 | int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) 79 | { 80 | if (RedisModule_Init(ctx, "h5g", 1, REDISMODULE_APIVER_1) == 81 | REDISMODULE_ERR) 82 | return REDISMODULE_ERR; 83 | 84 | if (RedisModule_CreateCommand(ctx, hproxy_flushdb_str, HProxyFlushDB, 85 | "", 1, 1, 1) == REDISMODULE_ERR) 86 | return REDISMODULE_ERR; 87 | 88 | if (RedisModule_RegisterCommandFilter(ctx, ProxyCommandFilter, 89 | REDISMODULE_CMDFILTER_NOSELF) == 90 | NULL) 91 | return REDISMODULE_ERR; 92 | 93 | return REDISMODULE_OK; 94 | } 95 | -------------------------------------------------------------------------------- /redis-module/load.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | redis-cli debug set-disable-deny-scripts 1 4 | redis-cli function delete h5g 5 | redis-cli -x function load < h5g_flushdb.lua 6 | -------------------------------------------------------------------------------- /redis-module/redis.conf: -------------------------------------------------------------------------------- 1 | loadmodule /tmp/module.so 2 | enable-debug-command yes 3 | -------------------------------------------------------------------------------- /regexp.stp: -------------------------------------------------------------------------------- 1 | # Regular Expression performance measuring tool 2 | # Compile: 3 | # stap -DSTP_NO_OVERLOAD regexp.stp -p4 -m pattern_performance 4 | # Run: 5 | # staprun pattern_performance.ko metric= refresh= 6 | # @ton31337 7 | 8 | global metric="pattern" 9 | global refresh=5 10 | global refresh_count=0 11 | global begin 12 | global most_pattern 13 | global most_time 14 | 15 | probe begin { print_head(); } 16 | probe process("/usr/local/openresty/nginx/sbin/nginx").function("msc_regexec_capture") 17 | { 18 | begin = gettimeofday_us(); 19 | most_pattern[user_string($regex->pattern)]++; 20 | } 21 | 22 | probe process("/usr/local/openresty/nginx/sbin/nginx").function("msc_regexec_capture").return 23 | { 24 | elapsed = gettimeofday_us() - begin; 25 | most_time[user_string($regex->pattern),$slen] = elapsed; 26 | } 27 | 28 | function print_head() 29 | { 30 | ansi_clear_screen(); 31 | printf("Probing...Type CTRL+C to stop probing.\n"); 32 | if(metric == "pattern") { 33 | printf("Count\t\tRegex\n"); 34 | } else { 35 | printf("Time(us)\t\tRegex (data length)\n"); 36 | } 37 | } 38 | 39 | function by_pattern() 40 | { 41 | foreach(pattern in most_pattern- limit 10) { 42 | printf("%d\t\t%s\n", most_pattern[pattern], pattern); 43 | } 44 | } 45 | 46 | function by_time() 47 | { 48 | foreach([pattern,len] in most_time- limit 10) { 49 | printf("%d\t\t\t%s (%d)\n", most_time[pattern,len], pattern, len); 50 | } 51 | } 52 | 53 | probe timer.s(1) 54 | { 55 | if(refresh_count++ % refresh) next 56 | print_head(); 57 | if(metric == "pattern") { 58 | by_pattern(); 59 | } else { 60 | by_time(); 61 | } 62 | } 63 | 64 | probe end 65 | { 66 | printf("Hope you are doing well ;-)\n"); 67 | delete most_time; 68 | delete most_pattern; 69 | delete begin; 70 | delete refresh_count; 71 | } 72 | -------------------------------------------------------------------------------- /rubygc.stp: -------------------------------------------------------------------------------- 1 | # ruby GC 2 | # @ton31337 3 | 4 | global times; 5 | global total; 6 | global nested; 7 | global gc; 8 | global slow_gc; 9 | global skip=1; 10 | 11 | probe process("/opt/rbenv/versions/2.2.2/bin/ruby").mark("gc__sweep__begin") 12 | { 13 | times[tid(), nested[tid()]++] = gettimeofday_us(); 14 | } 15 | 16 | probe process("/opt/rbenv/versions/2.2.2/bin/ruby").mark("gc__sweep__end") 17 | { 18 | ftime = times[tid(), --nested[tid()]]; 19 | etime = gettimeofday_us() - ftime; 20 | gc <<< etime; 21 | if (etime > 1000000) { 22 | slow_gc[etime] = ctime(gettimeofday_s()); 23 | skip = 0; 24 | } 25 | } 26 | 27 | probe timer.s(1) 28 | { 29 | ansi_clear_screen(); 30 | printf("GC %d run/s\n", @count(gc)); 31 | printf("GC average took <%d.%06d>\n", (@avg(gc) / 1000000), (@avg(gc) % 1000000)); 32 | printf("\nGC in real-time (microseconds) \n"); 33 | printf("=================================\n"); 34 | print(@hist_linear(gc, 0, 200, 10)); 35 | total += @count(gc); 36 | 37 | delete gc; 38 | } 39 | 40 | probe timer.s(30) 41 | { 42 | printf("Total runs per minute: %d\n", total); 43 | 44 | if (!skip) { 45 | printf("Slowest runs: \n"); 46 | foreach(etime in slow_gc- limit 10) { 47 | printf("%s <%d.%06d>\n", slow_gc[etime], (etime / 1000000), (etime % 1000000)); 48 | } 49 | } 50 | exit(); 51 | } 52 | -------------------------------------------------------------------------------- /rubytop.stp: -------------------------------------------------------------------------------- 1 | # yum install systemtap-sdt-devel -y 2 | # CONFIGURE_OPTS="--enable-dtrace" rbenv install 2.1.3 3 | # stap rubytop.stp -DMAXMAPENTRIES=10240 -p4 -m rubytop 4 | # staprun rubytop sort_etime=<0|1> num= refresh= 5 | # @ton31337 6 | 7 | global calls; 8 | global etimes; 9 | global sort_etime=0; 10 | global num=20; 11 | global refresh=1; 12 | global timer=0; 13 | 14 | @define skip(x,y) %( if(isinstr(@x, @y)) next; %) 15 | @define stats %( printf("<%d.%06d> tid:%-8d count:%-8d [%s#%s] %s:%d\n", 16 | (etime / 1000000), (etime % 1000000), 17 | tid, calls[tid, class, method, file, line, etime], class, method, file, line) %) 18 | 19 | function print_head() 20 | { 21 | ansi_clear_screen(); 22 | printf("Probing...Type CTRL+C to stop probing.\n"); 23 | } 24 | 25 | function print_stats() 26 | { 27 | if(sort_etime) { 28 | foreach([tid, class, method, file, line, etime-] in calls limit num) 29 | @stats; 30 | } else { 31 | foreach([tid, class, method, file, line, etime] in calls- limit num) 32 | @stats; 33 | } 34 | } 35 | 36 | probe process("/opt/rbenv/versions/2.2.2/bin/ruby").mark("method__entry") 37 | { 38 | class = user_string($arg1); 39 | method = user_string($arg2); 40 | @skip(class, "Kernel"); 41 | etimes[tid(), class, method] = gettimeofday_us(); 42 | } 43 | 44 | probe process("/opt/rbenv/versions/2.2.2/bin/ruby").mark("method__return") 45 | { 46 | class = user_string($arg1); 47 | method = user_string($arg2); 48 | file = user_string($arg3); 49 | line = $arg4; 50 | @skip(class, "Kernel"); 51 | etime = gettimeofday_us() - etimes[tid(), class, method]; 52 | if (!etimes[tid(), class, method]) 53 | next; 54 | 55 | calls[tid(), class, method, file, line, etime]++; 56 | } 57 | 58 | probe timer.s(1) { 59 | if (timer++ % refresh) next; 60 | print_head(); 61 | print_stats(); 62 | } 63 | 64 | probe timer.s(60), end { 65 | delete calls; 66 | delete etimes; 67 | } 68 | -------------------------------------------------------------------------------- /rx_discards.stp: -------------------------------------------------------------------------------- 1 | # ethtool -S eth0 | grep rx_disca 2 | # stap -d tg3 rx_discards.stp -m discards -p4 -g 3 | # @ton31337 4 | 5 | %{ 6 | #include 7 | %} 8 | 9 | probe begin 10 | { 11 | ansi_clear_screen(); 12 | printf("Probing...Type CTRL+C to stop probing.\n"); 13 | } 14 | 15 | probe kernel.function("netif_receive_skb").return, 16 | kernel.function("netif_rx").return 17 | { 18 | if ($return == %{ NET_RX_DROP %}) { 19 | printf("#### %s ####\n", ctime(gettimeofday_s())); 20 | print_backtrace(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rx_dropped.stp: -------------------------------------------------------------------------------- 1 | # drivers/net/tg3.c:6830: 2 | # drop_it_no_recycle: 3 | # /* Other statistics kept track of by card. */ 4 | # tp->rx_dropped++; 5 | # goto next_pkt; 6 | # } 7 | # @ton31337 8 | # see who generates drops at tg3 driver 9 | 10 | probe module("tg3").statement("tg3_rx@drivers/net/tg3.c:6830") 11 | { 12 | printf("#### %s ####", ctime(gettimeofday_s())); 13 | printf("rx_dropped: %d\n", $tp->rx_dropped); 14 | print_backtrace(); 15 | } 16 | -------------------------------------------------------------------------------- /sentinel.md: -------------------------------------------------------------------------------- 1 | Every time Redis is doing failover, it calls `sentinelStartFailover()`. Sentinels exchange hello messages using Pub/Sub and updates `last_pub_time` variable. So, let's dig more into this. Here is the snippet ([Systemtap](https://sourceware.org/systemtap/)) I used to probe user-space: 2 | ``` 3 | probe process("/usr/local/bin/redis-server").function("sentinelStartFailover") 4 | { 5 | elapsed = gettimeofday_ms() - $master->last_pub_time 6 | printf("%d.%03ds\n", 7 | (elapsed / 1000), (elapsed % 1000)); 8 | } 9 | ``` 10 | 11 | ### Manual failover using redis-cli 12 | ``` 13 | 127.0.0.1:16380> sentinel failover sentinel_de 14 | OK 15 | ``` 16 | Another console: 17 | ``` 18 | [root@redis-node1 ~]# stap sentinel.stp 19 | 0.835s 20 | ``` 21 | 22 | ### /etc/init.d/redis-de stop 23 | ``` 24 | [root@redis-node1 ~]# /etc/init.d/redis-de stop 25 | Stopping ... 26 | Redis stopped 27 | ``` 28 | Another console: 29 | ``` 30 | [root@redis-node1 ~]# stap sentinel.stp 31 | 5.843s 32 | ``` 33 | -------------------------------------------------------------------------------- /slow_start_check.stp: -------------------------------------------------------------------------------- 1 | # get the number of how much times was tcp_cwnd_restart called 2 | # get real-time stats for cwnd 3 | # use sysctl -w net.ipv4.tcp_slow_start_after_idle=0 (default 1) 4 | # @ton31337 5 | 6 | %{ 7 | #include 8 | %} 9 | 10 | global count; 11 | global etime; 12 | 13 | function get_cwnd:long(sk:long) 14 | %{ 15 | struct tcp_sock *tp = tcp_sk((struct sock *)STAP_ARG_sk); 16 | u32 cwnd = tp->snd_cwnd; 17 | THIS->__retvalue = cwnd; 18 | %} 19 | 20 | probe begin 21 | { 22 | etime = gettimeofday_s(); 23 | } 24 | 25 | probe kernel.function("tcp_cwnd_restart") 26 | { 27 | count++; 28 | printf("congestion window size: %d\n", get_cwnd($sk)); 29 | } 30 | 31 | probe kernel.function("tcp_ack").return 32 | { 33 | printf("Window size prior recovery: %d\n", $prior_cwnd); 34 | } 35 | 36 | probe timer.s(2) 37 | { 38 | ansi_clear_screen(); 39 | } 40 | 41 | probe end 42 | { 43 | etime = gettimeofday_s() - etime; 44 | printf("\ntcp_cwnd_restart called %d times in %d seconds.\n", count, etime); 45 | delete count; 46 | delete etime; 47 | } 48 | -------------------------------------------------------------------------------- /so_keepalives.stp: -------------------------------------------------------------------------------- 1 | # show sockets using SO_KEEPALIVE option 2 | # @ton31337 3 | 4 | %{ 5 | #include 6 | %} 7 | 8 | global fds; 9 | 10 | probe begin,timer.s(30) 11 | { 12 | delete fds; 13 | ansi_clear_screen(); 14 | } 15 | 16 | probe kernel.function("sys_connect") 17 | { 18 | fds[pid(), $fd, "host"] = $uservaddr; 19 | fds[pid(), $fd, "len"] = $addrlen; 20 | } 21 | 22 | probe kernel.function("sys_setsockopt").return 23 | { 24 | if ($optname == %{ SO_KEEPALIVE %} && $return == 0) { 25 | host = fds[pid(), $fd, "host"]; 26 | len = fds[pid(), $fd, "len"]; 27 | printf("%s %20s %7d %24s fd:%d\n", 28 | ctime(gettimeofday_s()), 29 | execname(), 30 | pid(), 31 | _struct_sockaddr_u_ip_addr(host, len), 32 | $fd); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /spam.stp: -------------------------------------------------------------------------------- 1 | # found the spammer if using not mail() function (e.g. php mail()) 2 | # stap spam.stp 3 | # @ton31337 4 | 5 | global _count; 6 | 7 | probe begin { printf("UID\tCOUNT\n"); } 8 | 9 | probe kernel.function("sys_sendto") 10 | { 11 | try { 12 | buf = kernel_string($buff); 13 | if(isinstr(buf, "MAIL FROM:") > 0) 14 | _count[uid()]++; 15 | } catch(err) {} 16 | } 17 | 18 | probe timer.s(3) 19 | { 20 | foreach(uid in _count- limit 5) 21 | printf("%d\t%d\n", uid, _count[uid]); 22 | } 23 | 24 | probe timer.s(30) { delete _count; } 25 | -------------------------------------------------------------------------------- /systemd-socket-activation/h5g-u1.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Requires=php-fpm-u1.service 3 | After=php-fpm-u1.service 4 | Requires=h5g-u1.socket 5 | After=h5g-u1.socket 6 | 7 | [Service] 8 | User=www-data 9 | Group=www-data 10 | ExecStart=/lib/systemd/systemd-socket-proxyd /tmp/u1-php-fpm.socket 11 | -------------------------------------------------------------------------------- /systemd-socket-activation/h5g-u1.socket: -------------------------------------------------------------------------------- 1 | [Socket] 2 | ListenStream=/tmp/u1-systemd.socket 3 | 4 | [Install] 5 | WantedBy=sockets.target 6 | -------------------------------------------------------------------------------- /systemd-socket-activation/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8081; 3 | 4 | root /var/www/u1; 5 | index index.html index.htm index.nginx-debian.html; 6 | server_name _; 7 | 8 | location / { 9 | try_files $uri $uri/ =404; 10 | } 11 | 12 | location ~ \.php$ { 13 | include snippets/fastcgi-php.conf; 14 | fastcgi_pass unix:/tmp/u1-systemd.socket; 15 | } 16 | } 17 | 18 | server { 19 | listen 8082; 20 | 21 | root /var/www/u2; 22 | index index.html index.htm index.nginx-debian.html; 23 | server_name _; 24 | 25 | location / { 26 | try_files $uri $uri/ =404; 27 | } 28 | 29 | location ~ \.php$ { 30 | include snippets/fastcgi-php.conf; 31 | fastcgi_pass unix:/tmp/u2-systemd.socket; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /systemd-socket-activation/php-fpm-u1.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | pid = /tmp/u1-php-fpm.pid 3 | error_log = /tmp/u1-php-fpm.log 4 | 5 | [www] 6 | user = www-data 7 | group = www-data 8 | listen = /tmp/u1-php-fpm.socket 9 | listen.owner = www-data 10 | listen.group = www-data 11 | pm = ondemand 12 | pm.max_children = 4 13 | -------------------------------------------------------------------------------- /systemd-socket-activation/php-fpm-u1.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | After=network.target 3 | 4 | [Service] 5 | Type=notify 6 | ExecStart=/usr/sbin/php-fpm7.4 --nodaemonize --fpm-config /etc/php/h5g/u1.conf 7 | ExecReload=/bin/kill -USR2 $MAINPID 8 | 9 | [Install] 10 | WantedBy=multi-user.target 11 | -------------------------------------------------------------------------------- /tcp_abc.stp: -------------------------------------------------------------------------------- 1 | # http://lxr.free-electrons.com/source/net/ipv4/tcp_input.c#L803 2 | # sysctl net.ipv4.tcp_abc (0|1|2) 3 | # stap -g iw.stp 4 | # @ton31337 5 | 6 | %{ 7 | #include 8 | %} 9 | 10 | function get_cwnd:long(dst:long) 11 | %{ 12 | __u32 cwnd = ((struct dst_entry *)STAP_ARG_dst ? 13 | dst_metric((struct dst_entry *)STAP_ARG_dst, RTAX_INITCWND) : 0); 14 | if(!cwnd) 15 | cwnd = TCP_INIT_CWND; 16 | THIS->__retvalue = cwnd; 17 | %} 18 | 19 | probe kernel.function("tcp_init_cwnd").return 20 | { 21 | printf("%d\n", get_cwnd($dst)); 22 | } 23 | -------------------------------------------------------------------------------- /tcp_abort_on_overflow.md: -------------------------------------------------------------------------------- 1 | ## What is tcp_abort_on_overflow? 2 | If listening service is too slow to accept new connections, reset them. Default state is FALSE. It means that if overflow occurred due to a burst, connection will recover. Enable this option _only_ if you are really sure that listening daemon cannot be tuned to accept connections faster. Enabling this option can harm clients of your server. 3 | 4 | ## More details #1 5 | After some analyzing kernel's [source](http://lxr.free-electrons.com/source/net/ipv4/tcp_minisocks.c#L757) I figured out what this [function](http://lxr.free-electrons.com/source/net/ipv4/tcp_minisocks.c#L559) actually do. If it can't create the child socket it just goes to [listen_overflow](http://lxr.free-electrons.com/source/net/ipv4/tcp_minisocks.c#L768). It returns [NULL](http://lxr.free-electrons.com/source/net/ipv4/tcp_minisocks.c#L790) if `tcp_abort_on_overflow` is disabled (default value), else it sets this packet as [ACK](http://lxr.free-electrons.com/source/net/ipv4/tcp_minisocks.c#L770) and returns NULL. 6 | 7 | ## More details #2 8 | I decided to verify how it's really works. I've setup custom web server with [listen](http://linux.die.net/man/2/listen) maximum backlog 5 and ran [ab](https://httpd.apache.org/docs/2.2/programs/ab.html) tool to generate traffic (to overflow backlog). 9 | 10 | ### Test #1 (sysctl -w net.ipv4.tcp_abort_on_overflow=0) 11 | ``` 12 | % ab -n 300 -c 100 http://X.X.X.X/ 13 | This is ApacheBench, Version 2.3 <$Revision: 1604373 $> 14 | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 15 | Licensed to The Apache Software Foundation, http://www.apache.org/ 16 | 17 | Benchmarking X.X.X.X (be patient) 18 | Completed 100 requests 19 | Completed 200 requests 20 | apr_pollset_poll: The timeout specified has expired (70007) 21 | Total of 294 requests completed 22 | ``` 23 | 24 | ### Test #2 (sysctl -w net.ipv4.tcp_abort_on_overflow=1) 25 | ``` 26 | % ab -n 300 -c 100 http://X.X.X.X/ 27 | This is ApacheBench, Version 2.3 <$Revision: 1604373 $> 28 | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 29 | Licensed to The Apache Software Foundation, http://www.apache.org/ 30 | 31 | Benchmarking X.X.X.X (be patient) 32 | Completed 100 requests 33 | Completed 200 requests 34 | Completed 300 requests 35 | Finished 300 requests 36 | 37 | 38 | Server Software: 39 | Server Hostname: X.X.X.X 40 | Server Port: 80 41 | 42 | Document Path: / 43 | Document Length: 13 bytes 44 | 45 | Concurrency Level: 100 46 | Time taken for tests: 4.630 seconds 47 | Complete requests: 300 48 | Failed requests: 61 49 | (Connect: 0, Receive: 0, Length: 61, Exceptions: 0) 50 | Total transferred: 23183 bytes 51 | HTML transferred: 3107 bytes 52 | Requests per second: 64.80 [#/sec] (mean) 53 | Time per request: 1543.185 [ms] (mean) 54 | Time per request: 15.432 [ms] (mean, across all concurrent requests) 55 | Transfer rate: 4.89 [Kbytes/sec] received 56 | 57 | Connection Times (ms) 58 | min mean[+/-sd] median max 59 | Connect: 0 823 1100.2 116 4437 60 | Processing: 4 100 273.5 46 3337 61 | Waiting: 0 42 57.4 15 246 62 | Total: 66 923 1128.7 317 4555 63 | ``` 64 | 65 | As you noticed first test just failed, due to overflowed backlog queue, the second passed without any burst. 66 | 67 | ## Debug 68 | As always I've used my favorite tool [Systemtap](https://sourceware.org/systemtap/). With this code I just probe function `tcp_check_req` at the exit point and check for two values: 69 | * `if return == NULL` 70 | * `if (inet_rsk(req)->acked == 1)` 71 | 72 | It means, that if these conditions are met, then `tcp_abort_on_overflow` is disabled and you should take some actions: increase backlog size or enable `tcp_abort_on_overflow` (carefully). 73 | 74 | ``` 75 | %{ 76 | #include 77 | %} 78 | 79 | function listen_overflow:long(req:long) 80 | %{ 81 | struct request_sock *req = (struct request_sock *)STAP_ARG_req; 82 | if (inet_rsk(req)->acked == 1) 83 | THIS->__retvalue = 1; 84 | %} 85 | 86 | probe kernel.function("tcp_check_req").return 87 | { 88 | if (!$return && listen_overflow($req)) { 89 | printf("listen overflow\n"); 90 | exit(); 91 | } 92 | } 93 | ``` 94 | 95 | ## Conclusion 96 | This post was made only to better understand what it is and how it works. 97 | -------------------------------------------------------------------------------- /tcp_mem.stp: -------------------------------------------------------------------------------- 1 | # show receive/send buffers (rmem, wmem) 2 | # show incoming queue (netdev_backlog) 3 | # sysctl net.ipv4.tcp_rmem 4 | # sysctl net.ipv4.tcp_wmem 5 | # @ton31337 6 | 7 | global _rcv; 8 | global _snd; 9 | global _rcv_queue; 10 | 11 | function print_head() 12 | { 13 | ansi_clear_screen(); 14 | println("Probing...Type CTRL+C to stop probing."); 15 | println("Buffer size\t\tCount\n"); 16 | } 17 | 18 | probe begin { print_head(); } 19 | probe kernel.function("tcp_v4_do_rcv"), kernel.function("tcp_v6_do_rcv") 20 | { 21 | family = (ppfunc() == "tcp_v4_do_rcv") ? "inet4" : "inet6"; 22 | _rcv[family, $sk->sk_rcvbuf]++; 23 | _snd[family, $sk->sk_sndbuf]++; 24 | _rcv_queue[family, cpu()] = $sk->sk_receive_queue->qlen; 25 | } 26 | 27 | probe timer.s(2) 28 | { 29 | print_head(); 30 | println("# READ"); 31 | foreach([family, buf] in _rcv- limit 10) { 32 | printf("%s buffer: %d bytes (%d Kbytes), count: %d\n", 33 | family, 34 | buf, 35 | (buf / 1024), 36 | _rcv[family, buf]); 37 | } 38 | 39 | println("\n# WRITE"); 40 | foreach([family, buf] in _snd- limit 10) { 41 | printf("%s buffer: %d bytes (%d Kbytes), count: %d\n", 42 | family, 43 | buf, 44 | (buf / 1024), 45 | _snd[family, buf]); 46 | } 47 | 48 | println("\n# RECEIVE QUEUES"); 49 | foreach([family, cpu] in _rcv_queue- limit 10) { 50 | printf("%s qlen: %d, cpu: %d\n", family, _rcv_queue[family, cpu], cpu); 51 | } 52 | 53 | delete _rcv; 54 | delete _snd; 55 | } 56 | -------------------------------------------------------------------------------- /tcp_slow_start.md: -------------------------------------------------------------------------------- 1 | ## What are these sysctl parameters? 2 | * tcp_slow_start_after_idle 3 | 4 | If set, provide RFC2861 behavior and time out the congestion window after an idle period. An idle period is defined at the current RTO. If unset, the congestion window will not be timed out after an idle period. Default: 1 5 | 6 | * tcp_no_metrics_save 7 | 8 | By default, TCP saves various connection metrics in the route cache when the connection closes, so that connections established in the near future can use these to set initial conditions. Usually, this increases overall performance, but may sometimes cause performance degradation. If set, TCP will not cache metrics on closing connections. 9 | 10 | ## Tests 11 | ### Test #1 (net.ipv4.tcp_slow_start_after_idle=0 / net.ipv4.tcp_no_metrics_save=0) 12 | ``` 13 | count: 16531, min: 5, max: 383, avg: 31 14 | ``` 15 | 16 | ### Test #2 (net.ipv4.tcp_slow_start_after_idle=1 / net.ipv4.tcp_no_metrics_save=0) 17 | ``` 18 | count: 15250, min: 5, max: 383, avg: 10 19 | ``` 20 | 21 | ### Test #3 (net.ipv4.tcp_slow_start_after_idle=0 / net.ipv4.tcp_no_metrics_save=1) 22 | ``` 23 | count: 15327, min: 5, max: 383, avg: 24 24 | ``` 25 | 26 | ### Test #4 (net.ipv4.tcp_slow_start_after_idle=1 / net.ipv4.tcp_no_metrics_save=1) 27 | ``` 28 | count: 15862, min: 5, max: 383, avg: 10 29 | ``` 30 | 31 | ## Results 32 | ![](http://donatas.net/slow_start_no_metrics.png) 33 | Looks like the first case has the best performance, while the second has the worst performance. Even if you have tcp_slow_start_after_idle disabled, enabling tcp_no_metrics_save will win some performance. 34 | 35 | ## Debug 36 | ``` 37 | /* 38 | Show how these tcp-sysctl parameters can boost TCP performance: 39 | net.ipv4.tcp_slow_start_after_idle 40 | net.ipv4.tcp_no_metrics_save 41 | Every time ACK is received, congestion window size is increased acording tcp_abc ip-sysctl parameter. 42 | 43 | @ton31337 44 | */ 45 | 46 | %{ 47 | #include 48 | %} 49 | 50 | global cwnd; 51 | global counter; 52 | global graph = 0; 53 | 54 | function get_cwnd:long(sk:long) 55 | %{ 56 | struct tcp_sock *tp = tcp_sk((struct sock *)STAP_ARG_sk); 57 | if (tp->snd_cwnd) 58 | THIS->__retvalue = tp->snd_cwnd; 59 | %} 60 | 61 | probe kernel.function("tcp_ack").return 62 | { 63 | cwnd <<< get_cwnd($sk); 64 | printf("%d\n", get_cwnd($sk)); 65 | if (graph) 66 | if (counter++ > 500) 67 | exit(); 68 | } 69 | 70 | probe timer.s(30) 71 | { 72 | printf("count: %d, min: %d, max: %d, avg: %d\n", 73 | @count(cwnd), @min(cwnd), @max(cwnd), @avg(cwnd)); 74 | exit(); 75 | } 76 | ``` 77 | -------------------------------------------------------------------------------- /tcp_timestamps.stp: -------------------------------------------------------------------------------- 1 | # PoC how disabling tcp timestamps we can save 12 bytes for every packet 2 | # net.ipv4.tcp_timestamps=0 3 | # @ton31337 4 | 5 | %{ 6 | #include 7 | %} 8 | 9 | global __tcp_header; 10 | 11 | function get_tcp_header_len:long(sk:long) 12 | %{ 13 | struct tcp_sock *tp = tcp_sk((struct sock *)STAP_ARG_sk); 14 | THIS->__retvalue = tp->tcp_header_len; 15 | %} 16 | 17 | probe kernel.function("tcp_connect_init").return 18 | { 19 | __tcp_header <<< get_tcp_header_len($sk); 20 | } 21 | 22 | probe timer.s(1) 23 | { 24 | ansi_clear_screen(); 25 | println("TCP Header length"); 26 | print(@hist_linear(__tcp_header, 20, 34, 2)); 27 | } 28 | -------------------------------------------------------------------------------- /tcp_tstamp_header_len.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ton31337/tools/68b9af990d55a0c3e7c4b003302cd5604bca9337/tcp_tstamp_header_len.mov -------------------------------------------------------------------------------- /ton_csgo.cfg: -------------------------------------------------------------------------------- 1 | rate "786432" 2 | cl_interp 0.031000" 3 | cl_interp_ratio "2" 4 | cl_cmdrate "128" 5 | cl_updaterate "128" 6 | fps_max "300" 7 | 8 | unbindall 9 | bind "0" "slot10" 10 | bind "a" "slot1" 11 | bind "s" "slot2" 12 | bind "d" "slot3" 13 | bind "w" "slot4" 14 | bind "v" "slot5" 15 | bind "q" "slot6" 16 | bind "f" "slot7" 17 | bind "c" "slot8" 18 | bind "9" "slot9" 19 | bind "z" "+moveleft" 20 | bind "b" "buymenu" 21 | bind "x" "+moveright" 22 | bind "e" "+use" 23 | bind "t" "+lookatweapon" 24 | bind "g" "drop" 25 | bind "i" "noclip" 26 | bind "k" "+voicerecord" 27 | bind "m" "teammenu" 28 | bind "r" "+reload" 29 | bind "shift" "+back" 30 | bind "o" "+spray_menu" 31 | bind "u" "messagemode2" 32 | bind "mouse2" "+forward" 33 | bind "y" "messagemode" 34 | bind "space" "+jump;-attack;-jump" 35 | bind "`" "toggleconsole" 36 | bind "\" "slot12" 37 | bind "TAB" "+showscores" 38 | bind "ESCAPE" "cancelselect" 39 | bind "DEL" "mute" 40 | bind "PAUSE" "pause" 41 | bind "alt" "+speed" 42 | bind "CTRL" "+duck" 43 | bind "F1" "autobuy" 44 | bind "F2" "rebuy" 45 | bind "F3" "host_framerate 0" 46 | bind "F4" "host_framerate 0.1" 47 | bind "F5" "jpeg" 48 | bind "F6" "save quick" 49 | bind "F7" "load quick" 50 | bind "F10" "quit prompt" 51 | bind "MOUSE1" "+attack" 52 | bind "MOUSE3" "+attack2" 53 | bind "MOUSE5" "player_ping" 54 | @panorama_debug_overlay_opacity "0.8" 55 | adsp_debug "0" 56 | ai_report_task_timings_on_limit "0" 57 | ai_think_limit_label "0" 58 | budget_averages_window "30" 59 | budget_background_alpha "128" 60 | budget_bargraph_background_alpha "128" 61 | budget_bargraph_range_ms "16.6666666667" 62 | budget_history_numsamplesvisible "100" 63 | budget_history_range_ms "66.666666667" 64 | budget_panel_bottom_of_history_fraction ".25" 65 | budget_panel_height "384" 66 | budget_panel_width "512" 67 | budget_panel_x "0" 68 | budget_panel_y "50" 69 | budget_peaks_window "30" 70 | budget_show_averages "0" 71 | budget_show_history "1" 72 | budget_show_peaks "1" 73 | bugreporter_uploadasync "0" 74 | bugreporter_username "" 75 | c_maxdistance "200" 76 | c_maxpitch "90" 77 | c_maxyaw "135" 78 | c_mindistance "30" 79 | c_minpitch "0" 80 | c_minyaw "-135" 81 | c_orthoheight "100" 82 | c_orthowidth "100" 83 | c_thirdpersonshoulder "false" 84 | c_thirdpersonshoulderaimdist "120.0" 85 | c_thirdpersonshoulderdist "40.0" 86 | c_thirdpersonshoulderheight "5.0" 87 | c_thirdpersonshoulderoffset "20.0" 88 | cachedvalue_count_partybrowser "1581038092" 89 | cachedvalue_count_teammates "1581074689" 90 | cam_collision "1" 91 | cam_idealdelta "4.0" 92 | cam_idealdist "150" 93 | cam_idealdistright "0" 94 | cam_idealdistup "0" 95 | cam_ideallag "4.0" 96 | cam_idealpitch "0" 97 | cam_idealyaw "0" 98 | cam_snapto "0" 99 | cc_lang "" 100 | cc_linger_time "1.0" 101 | cc_predisplay_time "0.25" 102 | cc_subtitles "0" 103 | chet_debug_idle "0" 104 | cl_allowdownload "1" 105 | cl_allowupload "1" 106 | cl_autohelp "1" 107 | cl_autowepswitch "0" 108 | cl_bob_lower_amt "21" 109 | cl_bobamt_lat "0.33" 110 | cl_bobamt_vert "0.14" 111 | cl_bobcycle "0.98" 112 | cl_chatfilter_version "1" 113 | cl_chatfilters "63" 114 | cl_clanid "0" 115 | cl_cmdrate "128" 116 | cl_color "1" 117 | cl_compass_enabled "1" 118 | cl_crosshaircolor 5; 119 | cl_crosshairdot 1; 120 | cl_crosshairgap -2; 121 | cl_crosshairsize 1; 122 | cl_crosshairstyle 5; 123 | cl_crosshairusealpha 1; 124 | cl_crosshairthickness 0; 125 | cl_crosshair_drawoutline 0; 126 | cl_crosshair_sniper_width 1; 127 | cl_crosshaircolor_r 0; 128 | cl_crosshaircolor_g 255; 129 | cl_crosshaircolor_b 170; 130 | cl_crosshairusealpha "1" 131 | cl_debugrumble "0" 132 | cl_detail_avoid_force "0.4" 133 | cl_detail_avoid_radius "64" 134 | cl_detail_avoid_recover_speed "0.25" 135 | cl_detail_max_sway "5" 136 | cl_disablefreezecam "0" 137 | cl_disablehtmlmotd "0" 138 | cl_dm_buyrandomweapons "0" 139 | cl_downloadfilter "all" 140 | cl_dz_playagain_auto_spectate "0" 141 | cl_embedded_stream_audio_volume "0" 142 | cl_embedded_stream_audio_volume_xmaster "0" 143 | cl_fixedcrosshairgap "3" 144 | cl_freezecampanel_position_dynamic "1" 145 | cl_grass_mip_bias "-0.5" 146 | cl_hide_avatar_images "" 147 | cl_hud_background_alpha "0.5" 148 | cl_hud_bomb_under_radar "0" 149 | cl_hud_color "2" 150 | cl_hud_healthammo_style "0" 151 | cl_hud_playercount_pos "0" 152 | cl_hud_playercount_showcount "0" 153 | cl_hud_radar_scale "0.83" 154 | cl_idealpitchscale "0.8" 155 | cl_inventory_saved_filter2 "all,not_defaultequipped" 156 | cl_inventory_saved_sort2 "inv_sort_rarity" 157 | cl_invites_only_friends "0" 158 | cl_invites_only_mainmenu "0" 159 | cl_itemimages_dynamically_generated "2" 160 | cl_join_advertise "1" 161 | cl_minimal_rtt_shadows "1" 162 | cl_mouselook "1" 163 | cl_mute_all_but_friends_and_party "0" 164 | cl_mute_enemy_team "0" 165 | cl_obs_interp_enable "1" 166 | cl_observercrosshair "1" 167 | cl_player_ping_mute "0" 168 | cl_playerspray_auto_apply "1" 169 | cl_promoted_settings_acknowledged "1:1581038284250" 170 | cl_quickinventory_lastinv "1" 171 | cl_quickinventory_line_update_speed "65.0f" 172 | cl_radar_always_centered "1" 173 | cl_radar_icon_scale_min "0.6" 174 | cl_radar_rotate "1" 175 | cl_radar_scale "0.450000" 176 | cl_radar_square_with_scoreboard "1" 177 | cl_radial_radio_tab "0" 178 | cl_radialmenu_deadzone_size "0.04" 179 | cl_righthand "1" 180 | cl_rumblescale "1.0" 181 | cl_sanitize_player_names "0" 182 | cl_scoreboard_mouse_enable_binding "+attack2" 183 | cl_scoreboard_survivors_always_on "0" 184 | cl_show_clan_in_death_notice "1" 185 | cl_showhelp "1" 186 | cl_showloadout "1" 187 | cl_showpluginmessages2 "0" 188 | cl_sniper_delay_unscope "0" 189 | cl_spec_follow_grenade_key "0" 190 | cl_spec_mode "5" 191 | cl_tablet_mapmode "1" 192 | cl_teamid_overhead_mode "2" 193 | cl_teammate_colors_show "1" 194 | cl_timeout "30" 195 | cl_updaterate "128" 196 | cl_use_opens_buy_menu "0" 197 | cl_versus_intro "1" 198 | cl_viewmodel_shift_left_amt "1.5" 199 | cl_viewmodel_shift_right_amt "0.75" 200 | closecaption "0" 201 | closeonbuy "1" 202 | commentary_firstrun "0" 203 | con_enable "1" 204 | crosshair "1" 205 | dsp_enhance_stereo "0" 206 | engine_no_focus_sleep "50" 207 | force_audio_english "0" 208 | func_break_max_pieces "15" 209 | g15_update_msec "250" 210 | gameinstructor_enable "0" 211 | hud_scaling "0.833000" 212 | hud_showtargetid "1" 213 | hud_takesshots "0" 214 | joy_accelmax "1.0" 215 | joy_accelscale "3.5" 216 | joy_accelscalepoly "0.4" 217 | joy_advanced "0" 218 | joy_advaxisr "0" 219 | joy_advaxisu "0" 220 | joy_advaxisv "0" 221 | joy_advaxisx "0" 222 | joy_advaxisy "0" 223 | joy_advaxisz "0" 224 | joy_autoaimdampen "0" 225 | joy_autoAimDampenMethod "0" 226 | joy_autoaimdampenrange "0" 227 | joy_axisbutton_threshold "0.3" 228 | joy_cfg_preset "1" 229 | joy_circle_correct "1" 230 | joy_curvepoint_1 "0.001" 231 | joy_curvepoint_2 "0.4" 232 | joy_curvepoint_3 "0.75" 233 | joy_curvepoint_4 "1" 234 | joy_curvepoint_end "2" 235 | joy_diagonalpov "0" 236 | joy_display_input "0" 237 | joy_forwardsensitivity "-1" 238 | joy_forwardthreshold "0.15" 239 | joy_gamma "0.2" 240 | joy_inverty "0" 241 | joy_lowend "1" 242 | joy_lowend_linear "0.55" 243 | joy_lowmap "1" 244 | joy_movement_stick "0" 245 | joy_name "joystick" 246 | joy_no_accel_jump "0" 247 | joy_pitchsensitivity "-1" 248 | joy_pitchthreshold "0.15" 249 | joy_response_look "0" 250 | joy_response_look_pitch "1" 251 | joy_response_move "1" 252 | joy_sensitive_step0 "0.1" 253 | joy_sensitive_step1 "0.4" 254 | joy_sensitive_step2 "0.90" 255 | joy_sidesensitivity "1" 256 | joy_sidethreshold "0.15" 257 | joy_wingmanwarrior_turnhack "0" 258 | joy_yawsensitivity "-1" 259 | joy_yawthreshold "0.15" 260 | joystick "0" 261 | joystick_force_disabled "1" 262 | joystick_force_disabled_set_from_options "1" 263 | key_bind_version "5" 264 | lobby_default_privacy_bits2 "1" 265 | lockMoveControllerRet "0" 266 | lookspring "0" 267 | lookstrafe "0" 268 | m_customaccel "0" 269 | m_customaccel_exponent "1.05" 270 | m_customaccel_max "0" 271 | m_customaccel_scale "0.04" 272 | m_forward "1" 273 | m_mouseaccel1 "0" 274 | m_mouseaccel2 "0" 275 | m_mousespeed "1" 276 | m_pitch "0.022" 277 | m_rawinput "1" 278 | m_side "0.8" 279 | m_yaw "0.022" 280 | mapoverview_icon_scale "1.0" 281 | mat_monitorgamma "1.690000" 282 | mat_monitorgamma_tv_enabled "0" 283 | mat_powersavingsmode "0" 284 | mat_queue_report "0" 285 | mat_spewalloc "0" 286 | mc_accel_band_size "0.5" 287 | mc_dead_zone_radius "0.06" 288 | mc_max_pitchrate "100.0" 289 | mc_max_yawrate "230.0" 290 | mm_csgo_community_search_players_min "3" 291 | mm_dedicated_search_maxping "50.000000" 292 | mm_server_search_lan_ports "27015,27016,27017,27018,27019,27020" 293 | muzzleflash_light "1" 294 | name "s1mple" 295 | net_allow_multicast "1" 296 | net_graph "1" 297 | net_graphheight "64" 298 | net_graphholdsvframerate "0" 299 | net_graphipc "0" 300 | net_graphmsecs "400" 301 | net_graphpos "1" 302 | net_graphproportionalfont "1" 303 | net_graphshowinterp "1" 304 | net_graphshowlatency "1" 305 | net_graphshowsvframerate "0" 306 | net_graphsolid "1" 307 | net_graphtext "1" 308 | net_maxroutable "1200" 309 | net_scale "5" 310 | net_steamcnx_allowrelay "1" 311 | npc_height_adjust "1" 312 | option_duck_method "0" 313 | option_speed_method "0" 314 | password "fnc" 315 | play_distance "1" 316 | player_botdifflast_s "2" 317 | player_teamplayedlast "2" 318 | r_drawmodelstatsoverlaymax "1.5" 319 | r_drawmodelstatsoverlaymin "0.1" 320 | r_drawtracers_firstperson "1" 321 | r_eyegloss "1" 322 | r_eyemove "1" 323 | r_eyeshift_x "0" 324 | r_eyeshift_y "0" 325 | r_eyeshift_z "0" 326 | r_eyesize "0" 327 | rate "786432.000000" 328 | safezonex "1.0" 329 | safezoney "1.0" 330 | sc_enable "1.0" 331 | sc_joystick_map "1" 332 | sc_pitch_sensitivity "1.0" 333 | sc_yaw_sensitivity "1.0" 334 | scene_showfaceto "0" 335 | scene_showlook "0" 336 | scene_showmoveto "0" 337 | scene_showunlock "0" 338 | sensitivity "1.4" 339 | sk_autoaim_mode "1" 340 | skill "1.000000" 341 | snd_deathcamera_volume "0.000000" 342 | snd_duckerattacktime "0.5" 343 | snd_duckerreleasetime "2.5" 344 | snd_duckerthreshold "0.15" 345 | snd_ducking_off "1" 346 | snd_ducktovolume "0.55" 347 | snd_dzmusic_volume "0.2" 348 | snd_hrtf_distance_behind "100" 349 | snd_hrtf_voice_delay "0.1" 350 | snd_hwcompat "0" 351 | snd_mapobjective_volume "0.000000" 352 | snd_menumusic_volume "0.000000" 353 | snd_mix_async "1" 354 | snd_mix_async_onetime_reset "1" 355 | snd_mixahead "0.025" 356 | snd_music_selection "1" 357 | snd_music_volume_onetime_reset_2 "1" 358 | snd_musicvolume_multiplier_inoverlay "0.000000" 359 | snd_mute_losefocus "1" 360 | snd_mute_mvp_music_live_players "0" 361 | snd_mvp_volume "0" 362 | snd_pitchquality "1" 363 | snd_roundend_volume "0.000000" 364 | snd_roundstart_volume "0.000000" 365 | snd_surround_speakers "0" 366 | snd_tensecondwarning_volume "0.000000" 367 | sound_device_override "{0.0.0.00000000}.{2bbfa805-71e8-4b9a-b3e8-4c4af0e670ce}" 368 | spec_replay_autostart "1" 369 | spec_show_xray "1" 370 | spec_usenumberkeys_nobinds "1" 371 | spec_xray_dropped_unoccluded "1" 372 | ss_splitmode "0" 373 | store_version "1" 374 | suitvolume "0.25" 375 | sv_log_onefile "0" 376 | sv_logbans "0" 377 | sv_logecho "1" 378 | sv_logfile "1" 379 | sv_logflush "0" 380 | sv_logsdir "logs" 381 | sv_noclipaccelerate "5" 382 | sv_noclipspeed "5" 383 | sv_pvsskipanimation "1" 384 | sv_skyname "cs_tibet" 385 | sv_specaccelerate "5" 386 | sv_specnoclip "1" 387 | sv_specspeed "3" 388 | sv_unlockedchapters "1" 389 | sv_voiceenable "1" 390 | test_convar "0" 391 | texture_budget_background_alpha "128" 392 | texture_budget_panel_bottom_of_history_fraction ".25" 393 | texture_budget_panel_height "284" 394 | texture_budget_panel_width "512" 395 | texture_budget_panel_x "0" 396 | texture_budget_panel_y "450" 397 | triple_monitor_mode "0" 398 | tv_nochat "1" 399 | ui_inventorysettings_recently_acknowledged "" 400 | ui_news_last_read_link "https://blog.counter-strike.net/index.php/2020/02/28450/" 401 | ui_playsettings_maps_listen_casual "random_classic" 402 | ui_playsettings_maps_listen_competitive "random_classic" 403 | ui_playsettings_maps_listen_deathmatch "random_classic" 404 | ui_playsettings_maps_listen_scrimcomp2v2 "mg_de_inferno" 405 | ui_playsettings_maps_listen_skirmish "mg_skirmish_flyingscoutsman" 406 | ui_playsettings_maps_official_casual "mg_casualsigma" 407 | ui_playsettings_maps_official_deathmatch "mg_casualsigma" 408 | ui_playsettings_maps_workshop "" 409 | ui_playsettings_mode_listen "casual" 410 | ui_playsettings_mode_official_v20 "casual" 411 | ui_playsettings_survival_solo "0" 412 | ui_playsettings_warmup_map_name "de_mirage" 413 | ui_popup_weaponupdate_version "1" 414 | ui_setting_advertiseforhire_auto "1" 415 | ui_setting_advertiseforhire_auto_last "/survival" 416 | ui_steam_overlay_notification_position "bottomright" 417 | ui_vanitysetting_loadoutslot_ct "heavy0" 418 | ui_vanitysetting_loadoutslot_t "rifle4" 419 | ui_vanitysetting_team "t" 420 | vgui_message_dialog_modal "1" 421 | viewmodel_fov "68" 422 | viewmodel_offset_x "2.500000" 423 | viewmodel_offset_y "0" 424 | viewmodel_offset_z "-1.500000" 425 | viewmodel_presetpos "3" 426 | viewmodel_recoil "0" 427 | voice_caster_enable "0" 428 | voice_caster_scale "1.000000" 429 | voice_enable "1" 430 | voice_forcemicrecord "1" 431 | voice_modenable "1" 432 | voice_positional "0" 433 | voice_scale "0.3" 434 | voice_system_enable "1" 435 | voice_threshold "2000" 436 | volume "0.414272" 437 | vprof_graphheight "256" 438 | vprof_graphwidth "512" 439 | vprof_unaccounted_limit "0.3" 440 | vprof_verbose "1" 441 | vprof_warningmsec "10" 442 | xbox_autothrottle "1" 443 | xbox_throttlebias "100" 444 | xbox_throttlespoof "200" 445 | zoom_sensitivity_ratio_joystick "1.0" 446 | zoom_sensitivity_ratio_mouse "1.000000" 447 | -------------------------------------------------------------------------------- /twemproxy_connections.stp: -------------------------------------------------------------------------------- 1 | # count twemproxy backend connections and timeouts 2 | global count; 3 | global total; 4 | global timeouts; 5 | global timedtotal; 6 | 7 | probe begin { print_head(); } 8 | 9 | function print_head() 10 | { 11 | ansi_clear_screen(); 12 | printf("Probing...Type CTRL+C to stop probing.\n"); 13 | } 14 | 15 | probe process("/usr/local/bin/nutcracker").function("server_connect").return 16 | { 17 | sname = user_string($server->name->data); 18 | etime = gettimeofday_ms() - @entry(gettimeofday_ms()); 19 | count[sname]++; 20 | if (etime > 100) 21 | timeouts[sname, etime] = ctime(gettimeofday_s()); 22 | } 23 | 24 | probe timer.s(1) 25 | { 26 | print_head(); 27 | 28 | foreach(mc in count- limit 64) { 29 | printf("%s\t%7.5d\n", mc, count[mc]); 30 | total += count[mc]; 31 | } 32 | printf("Total connections: %d\n", total); 33 | println("--------------------------------"); 34 | foreach([sname, etime] in timeouts-) { 35 | printf("%s %s %d ms\n", timeouts[sname, etime], sname, etime); 36 | timedtotal++; 37 | } 38 | printf("Timed out connections: %d\n", timedtotal); 39 | 40 | delete count; 41 | delete total; 42 | } 43 | 44 | probe end 45 | { 46 | delete count; 47 | delete total; 48 | delete timeouts; 49 | } 50 | -------------------------------------------------------------------------------- /twemproxy_err.stp: -------------------------------------------------------------------------------- 1 | # by default these are ignored and not collected 2 | # case EPIPE: 3 | # case EINVAL: 4 | # case ECONNRESET: 5 | # case ECONNABORTED: 6 | # case ECONNREFUSED: 7 | # case ENOTCONN: 8 | # case ENETDOWN: 9 | # case ENETUNREACH: 10 | # case EHOSTDOWN: 11 | # case EHOSTUNREACH: 12 | # @ton31337 13 | 14 | probe begin 15 | { 16 | ansi_clear_screen(); 17 | printf("Date\t\t\t\tServer(connection_id)\t\t\tError\n"); 18 | } 19 | 20 | probe process("/usr/local/bin/nutcracker").function("server_close") 21 | { 22 | server_name = user_string(@cast($conn->owner, "server")->name->data); 23 | strerr = errno_str($conn->err); 24 | if($conn->err) 25 | printf("%s\t%s(%d)\t%s (r:%d s:%d)\n", 26 | ctime(gettimeofday_s()), 27 | server_name, 28 | $conn, 29 | strerr, 30 | $conn->recv_bytes, 31 | $conn->send_bytes); 32 | } 33 | -------------------------------------------------------------------------------- /twemproxy_mbuf.stp: -------------------------------------------------------------------------------- 1 | # show mbuf usage 2 | # Using twemproxy's default mbuf size of 16Kbytes, we waste lot of memory. 3 | # We allocate always mbuf with 16Kbytes, but we use only let's say 2KBytes, rest of memory is wasted. 4 | # If we change this to 512bytes, we save kernel's memory, we have higher connection rate, but we suffer more read/write() 5 | # @ton31337 6 | 7 | global mbuf_size; 8 | global INC_NUM; 9 | global RANGE_BY; 10 | 11 | function print_head() 12 | { 13 | ansi_clear_screen(); 14 | printf("Probing...Type CTRL+C to stop probing.\n"); 15 | } 16 | 17 | probe begin 18 | { 19 | RANGE_BY = 1024; 20 | INC_NUM = RANGE_BY - 1; 21 | } 22 | 23 | probe process("/usr/local/bin/nutcracker").function("mbuf_length").return 24 | { 25 | j = 0; 26 | for(i = 1; i <= 16; i++) { 27 | if(($return > j) && ($return < j+INC_NUM)) 28 | mbuf_size[i]++; 29 | j += RANGE_BY; 30 | } 31 | } 32 | 33 | probe timer.s(1) 34 | { 35 | print_head(); 36 | printf("Mbuf_range\tCount\n"); 37 | j = 0; 38 | for(i = 1; i <= 16; i++) { 39 | printf("%5d-%d\t%d\n", j, j+INC_NUM, mbuf_size[i]); 40 | j += RANGE_BY; 41 | } 42 | delete mbuf_size; 43 | } 44 | -------------------------------------------------------------------------------- /twemproxy_messages.stp: -------------------------------------------------------------------------------- 1 | # show value length, mbuf length for each message 2 | # @ton31337 3 | probe process("/usr/local/bin/nutcracker").function("msg_recv_chain") 4 | { 5 | if($msg->vlen) { 6 | server_name = user_string(@cast($conn->owner, "server")->name->data); 7 | printf("%s %s(%d) vlen:%d, mlen:%d\n", 8 | ctime(gettimeofday_s()), 9 | server_name, 10 | $conn, 11 | $msg->vlen, 12 | $msg->mlen 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /twemproxy_timeouts.stp: -------------------------------------------------------------------------------- 1 | # twemproxy keeps persistent connections after restart 2 | # socket_count = (server_connections * number_of_backend_servers) 3 | # need to check how much time (ms) takes connect() when timeouts 4 | 5 | global count; 6 | 7 | probe process("/usr/local/bin/nutcracker").function("server_connect") 8 | { 9 | _sname = user_string($server->name->data); 10 | count[_sname] = gettimeofday_ms(); 11 | } 12 | 13 | probe process("/usr/local/bin/nutcracker").function("server_connect").return 14 | { 15 | _sname = user_string($server->name->data); 16 | if(count[_sname]) { 17 | delta = gettimeofday_ms() - count[_sname]; 18 | if(delta > 1) 19 | printf("%s [ delta=%d, return=%d ]\n", _sname, delta, $return); 20 | } 21 | } 22 | 23 | probe timer.s(60) { delete count; } 24 | probe end { delete count; } 25 | -------------------------------------------------------------------------------- /twemstats.rb: -------------------------------------------------------------------------------- 1 | #!/opt/rbenv/shims/ruby 2 | 3 | require 'socket' 4 | require 'json' 5 | 6 | stats = {} 7 | s_stats = {} 8 | req_stats = {} 9 | res_stats = {} 10 | cur_conn = 0 11 | total = 0 12 | 13 | exit! if ARGV[0].nil? 14 | 15 | conn = TCPSocket.new '0.0.0.0', 22222 16 | while stream = conn.gets 17 | stats = JSON.parse(stream) 18 | end 19 | 20 | # Collect stats 21 | stats.map { |x| 22 | x.map { |cluster| 23 | if cluster.instance_of? Hash 24 | if cluster['client_connections'].to_i > 0 25 | cur_conn = cluster['client_connections'].to_i 26 | cluster.map { |s_key,s_val| 27 | if s_val.instance_of? Hash 28 | num_of_times_server_was_ejected = ((s_val['server_err'] + s_val['server_timedout'] + s_val['server_eof']) / ARGV[0].to_i) 29 | s_stats.merge!(s_key => num_of_times_server_was_ejected) 30 | req_stats.merge!(s_key => (s_val['request_bytes'] / s_val['requests'])) 31 | res_stats.merge!(s_key => (s_val['response_bytes'] / s_val['responses'])) 32 | end 33 | } 34 | end 35 | end 36 | } 37 | } 38 | 39 | # Print stats 40 | max_size = (s_stats.max_by { |k,v| v }.last > 0) ? s_stats.max_by { |k,v| v }.last : 1 41 | s_stats.map { |srv,count| 42 | print "#{srv.split('.').first} E=#{count} (#{(100 * count) / max_size}%), ReqS=#{req_stats[srv]} ResS=#{res_stats[srv]}\n" 43 | total += count 44 | } 45 | print "Total ejection count: #{total}\n" 46 | print "Total current connections: #{cur_conn}\n" 47 | -------------------------------------------------------------------------------- /validate.rake: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'neatjson' 3 | 4 | bs_version = '>= 0' 5 | gem 'berkshelf', bs_version 6 | 7 | namespace :validate do 8 | desc 'Validate files' 9 | 10 | task :validate do |_| 11 | `git diff --name-only HEAD^!`.split.each do |file| 12 | next unless File.exist?(file) 13 | next unless file.include?('json') 14 | 15 | id = File.basename(file, '.json') 16 | json = validate_json(file) 17 | 18 | validate_json_indentation(file, json, File.basename(file)) 19 | 20 | if file.include?('roles') 21 | validate_role_name(id, json) 22 | elsif file.include?('data_bags') 23 | validate_data_bag_id(id, json) 24 | end 25 | end 26 | end 27 | 28 | def validate_json(file) 29 | JSON.parse(File.read(file)) 30 | rescue JSON::ParserError 31 | puts "❌ JSON file #{file} is not valid." 32 | exit 1 33 | end 34 | 35 | def validate_json_indentation(file, json, file_name) 36 | old_file = "/tmp/#{file_name}.old" 37 | new_file = "/tmp/#{file_name}.new" 38 | write_files(file, json, old_file, new_file) 39 | if system("git diff --exit-code #{old_file} #{new_file}") == false 40 | puts "❌ JSON file #{file} has some issues. Please fix them." 41 | exit 1 42 | end 43 | delete_files(old_file, new_file) 44 | end 45 | 46 | def write_files(file, json, old_file, new_file) 47 | File.write(old_file, File.read(file)) 48 | File.write(new_file, JSON.neat_generate(json, after_comma: 1, 49 | after_colon: 1, 50 | wrap: true, 51 | indent: ' ') + "\n") 52 | end 53 | 54 | def delete_files(*files) 55 | files.each do |file| 56 | File.delete(file) 57 | end 58 | end 59 | 60 | def validate_role_name(name, json) 61 | return if json['name'] == name 62 | 63 | puts "❌ role's name '#{json['name']}' does not match file name '#{name}'." 64 | exit 1 65 | end 66 | 67 | def validate_data_bag_id(name, json) 68 | return if json['id'] == name 69 | 70 | puts "❌ data_bag's id '#{json['id']}' does not match file name '#{name}'." 71 | exit 1 72 | end 73 | end 74 | --------------------------------------------------------------------------------