Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
lvyahui8 committed Nov 14, 2024
1 parent 5d5a2d4 commit 0e241bd
Show file tree
Hide file tree
Showing 4 changed files with 629 additions and 36 deletions.
Binary file modified .assets/graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
129 changes: 100 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,121 @@
# ellyn
# Ellyn - Go 覆盖率、调用链数据采集工具

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Go Report Card](https://goreportcard.com/badge/github.com/lvyahui8/ellyn)](https://goreportcard.com/report/github.com/lvyahui8/ellyn)
[![codecov](https://codecov.io/gh/lvyahui8/ellyn/graph/badge.svg?token=YBV3TH2HQU)](https://codecov.io/gh/lvyahui8/ellyn)

### 功能特性

### Requires
- 支持收集全局覆盖数据(计算增量、全量覆盖率)
- 支持收集函数调用链(包含异步链路)
- 支持收集运行时数据(出入参、异常、耗时等)
- 支持收集单个请求粒度的上述数据
- 支持并发收集
- ~~支持配置方法mock~~


### 应用场景

- 覆盖率统计
- 调用链收集
- 数据(字段)血缘
- 流量观测
- 流量回放
- Mock
- 单测、自动化测试(获取单个用例覆盖明细)
- 精准测试
- 风险分析
- 统一监控告警(metrics)
- etc

### 运行环境

- Go Version >= 1.18
- Linux\Windows\MacOS

### 演示程序

[下载example演示程序](https://github.com/lvyahui8/ellyn/releases)

下载对应系统版本执行,然后访问[http://localhost:19898](http://localhost:19898)即可

![调用链](./.assets/graph.png)

### 工具使用方法

[下载ellyn工具](https://github.com/lvyahui8/ellyn/releases)

Usage
```text
NAME:
ellyn - Go coverage and callgraph collection tool
### Artifacts
USAGE:
ellyn [global options] command [command options]
- [ellyn](https://github.com/lvyahui8/ellyn/releases) : 命令行工具
- [example_app](https://github.com/lvyahui8/ellyn/releases) : 演示程序,下载执行,然后访问``http://localhost:19898``即可
COMMANDS:
update update code
rollback rollback code
help, h Shows a list of commands or help for one command
### Abilities
GLOBAL OPTIONS:
--help, -h show help
```

在目标go项目main package所在目录执行

### key
- ellyn update: 代码插桩,插桩之后编译代码启动服务,即可收集数据
- ellyn rollback: 回滚原文件,清理插桩痕迹

### 二次开发

#### 目录说明

- api: 提供运行时访问sdk(插桩代码)的api
- benchmark: 性能基准测试,对比各种场景不同采样率下的性能差异
- cmd: ellyn命令行工具,用于对目标项目执行插桩
- example: 演示程序。演示数据采集效果
- instr: 插桩逻辑,遍历目标项目文件,植入ellyn sdk代码
- sdk: 插桩代码调用的sdk,此目录拷贝到目标项目,作为目标项目的一部分参与编译。此目录不能使用非go官方依赖(test文件除外)
- test: 项目测试基础代码
- viewer: 简易版的可视化页面

#### 开发要点

- 避免资源冲突/锁竞争, 无锁优先
- 核心函数必须O(1)操作
- 高频访问的元素必须缓存行填充
- 牺牲部分空间换时间
- 尽量用array而非map
- 参数分析、收集要考虑值传递对性能影响
- 对象复用,减少gc对性能的影响
- etc
- 高频访问的字段必须缓存行填充,防止伪共享
- 可以牺牲部分空间换时间
- 尽量用array/bitmap而非go官方map
- 高频创建使用的对象基于sync.Pool池化,减少gc压力
- 参数收集要考虑大值传递(拷贝)对性能影响

#### Sdk组件及用途

- [RingBuffer ](./sdk/common/collections/ringbuffer.go) : 缓冲流量数据
- [RingBuffer性能测试](./sdk/common/collections/ringbuffer.md)
- [RingBuffer与Map性能对比测试](./sdk/common/collections/ring_buffer_vs_map.md)
- [LinkedQueue](./sdk/common/collections/linked_queue.go): 基于链表的同步队列。用作协程池的任务队列
- [hmap(SegmentHashmap)](./sdk/common/collections/hmap.go): 实现高性能的routineLocal
- [hmap性能测试](./sdk/common/collections/hmap.md)
- [bitmap](./sdk/common/collections/bitmap.go): 记录函数、块的执行情况
- [UnsafeCompressedStack](./sdk/common/collections/stack.go) : 模拟入栈弹栈
- [Stack性能测试](./sdk/common/collections/stack.md)
- [routineLocal/GLS/GoRoutineLocalStorage](./sdk/common/goroutine/routine_local.go): 缓存上下文
- [routineLocal性能测试](./sdk/common/goroutine/routine_local_test.go)
- [routinePool](./sdk/common/goroutine/routine_pool.go): 协程池,并发处理文件
- [Uint64GUIDGenerator](./sdk/common/guid/guid.go): 生成流量id


### 性能测试

- 对CPU密集型场景存在一定影响,即使采样率很低
- 对IO密集型场景影响很小,即使采样率很高

[明细数据](./benchmark/result.md)

### Sdk组件及用途

- [RingBuffer ](./ellyn_common/collections/ringbuffer.go) : 缓冲流量数据
- [RingBuffer性能测试](./ellyn_common/collections/ringbuffer.md)
- [LinkedQueue](./ellyn_common/collections/linked_queue.go): 基于链表的同步队列。用作协程池的任务队列
- [hmap(SegmentHashmap)](./ellyn_common/collections/hmap.go): 实现高性能的routineLocal
- [hmap性能测试](./ellyn_common/collections/hmap.md)
- [bitmap](./ellyn_common/collections/bitmap.go): 记录函数、块的执行情况
- [UnsafeCompressedStack](./ellyn_common/collections/stack.go) : 模拟入栈弹栈
- [Stack性能测试](./ellyn_common/collections/stack.md)
- [routineLocal/GLS/GoRoutineLocalStorage](./ellyn_common/goroutine/routine_local.go): 缓存上下文
- [routineLocal性能测试](./ellyn_common/goroutine/routine_local_test.go)
- [routinePool](./ellyn_common/goroutine/routine_pool.go): 协程池,并发处理文件
- [Uint64GUIDGenerator](./ellyn_common/guid/guid.go)
- [RingBuffer与Map性能对比测试](./ellyn_common/collections/ring_buffer_vs_map.md)
### Q&A

#### Q:为什么要实现部分集合库,而不是直接使用开源方案?

A: 这部分实现会拷贝到目标仓库,为确保不与目标仓库sdk冲突,所以自行实现。对于不拷贝的目标仓库的代码,优先考虑用复用开源实现
A: 这部分实现会拷贝到目标仓库,一是为确保不与目标仓库sdk冲突,二是针对当前场景做性能优化,因此自行实现。对于不拷贝的目标仓库的代码,优先考虑用复用开源实现
26 changes: 19 additions & 7 deletions benchmark/benchmark.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,30 @@ if ! [ -x "$(command -v benchstat)" ]; then
fi


cd "$SCRIPT_DIR/.." && go test -v -run TestRollbackBenchmark ./instr/
cd "$SCRIPT_DIR/.." && go test -run TestRollbackBenchmark ./instr/

cd "$SCRIPT_DIR/" && go test -run ^$ -bench=. -benchmem -benchtime=5s . > old.out

echo "### 基准"

echo '```text'
cat old.out
echo '```'

cd "$SCRIPT_DIR/" && go test -v -run ^$ -bench=. -benchmem -benchtime=5s . > old.out

sampling_rate_list=(0 0.0001 0.001 0.01 0.1 1)

for i in "${!sampling_rate_list[@]}";
do
for i in "${!sampling_rate_list[@]}"; do
echo "### 采样率 ${sampling_rate_list[$i]}"
out_file=new${i}.out
cd "$SCRIPT_DIR/.." && go test -v -run TestUpdateBenchmark ./instr/ "${sampling_rate_list[$i]}"
cd "$SCRIPT_DIR/" && go test -v -run ^$ -bench=. -benchmem -benchtime=5s . > "$out_file"
cat old.out "$out_file"
cd "$SCRIPT_DIR/../instr" && go test -test.paniconexit0 -test.run '^\QTestUpdateBenchmark\E$' ${sampling_rate_list[$i]}
cd "$SCRIPT_DIR/" && go test -run ^$ -bench=. -benchmem -benchtime=5s . > "$out_file"
echo '```text'
cat "$out_file"
echo '```'

echo '性能差异'
echo '```text'
benchstat old.out "$out_file"
echo '```'
done
Loading

0 comments on commit 0e241bd

Please sign in to comment.