Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kislerdm/color_theory_app-wasm
A ML demo webapp with logic running entirely on the client. It's a rework of https://github.com/kislerdm/color_theory_app
https://github.com/kislerdm/color_theory_app-wasm
golang machine-learning vanila-javascript wasm xgboost
Last synced: about 1 month ago
JSON representation
A ML demo webapp with logic running entirely on the client. It's a rework of https://github.com/kislerdm/color_theory_app
- Host: GitHub
- URL: https://github.com/kislerdm/color_theory_app-wasm
- Owner: kislerdm
- License: mit
- Created: 2022-08-11T23:08:27.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2022-08-17T21:19:04.000Z (over 2 years ago)
- Last Synced: 2024-06-21T19:08:46.240Z (8 months ago)
- Topics: golang, machine-learning, vanila-javascript, wasm, xgboost
- Language: Go
- Homepage: https://color-theory-app-wasm.dkisler.com
- Size: 133 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Color Theory App - WASM
Carnation of the [Color Theory App](https://github.com/kislerdm/color_theory_app) with two main differences:
- Logic is executed entirely on the client;
- Interface is implemented using vanilla JS instead of ReactJS.## Assets size minification
Total volume of assets data transferred to the client over the network is an important subject for optimisation.
Note that the volume is assesses by using `wc -c`.
### .wasm file
| Compiler | Volume [bytes] | Comment |
|:-----------------------------:|---------------:|:---------------------------------------------------------------------------------------------------------------|
| Default Go build | 2229903 | - |
| [tinygo](https://tinygo.org/) | 516864 | - |
| [tinygo](https://tinygo.org/) | 343122 | Removed dependency on `fmt` |
| [tinygo](https://tinygo.org/) | 157227 | Removed dependency on `fmt`
Build flags: `-gc=leaking -opt=2 -no-debug -panic=trap` |One can see that the logic refactoring, use of different compiler with configuration tweaks leads to the binary's size reduction by the factor of **~14** (!).
More adjustments and configuration tweaks may lead to further binary size cut.
Although any further effort investment shall be considered carefully since its ROI may not be as high.In case binary size is of critical importance, `rust` could be considered as the language which may potentially yield the wasm binary of under 50kB.
Note that the tinygo compiler does not [support](https://tinygo.org/docs/reference/lang-support/) reflection, hence the logic had to be adjusted to avoid using `encoding/json` and `encoding/csv`:
- [Code generator for model definition](./internal/colortype/train/main.go) is used to convert the JSON model definition to the native Go struct;
- [Code generator for colors names](./internal/colorname/data/main.go) is used to convert the CSV color names map to the native Go struct.### wasm_exec.js
| Description | Volume [bytes] | Comment |
|:-----------:|---------------:|:--------|
| Default | 18669 | - |
| TinyGo | 16001 | - |## Performance optimisation
### [colorname](./internal/colorname)
```bash
go test -bench=. -benchmem ./internal/colorname
goos: darwin
goarch: arm64
pkg: github.com/kislerdm/color_theory_app-wasm/internal/colorname
BenchmarkFindColorNameByRGB-10 6038 196192 ns/op 8046 B/op 9 allocs/op
BenchmarkFindColorNameByRGBv2-10 135073 8787 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/kislerdm/color_theory_app-wasm/internal/colorname 3.554s
```The logic rework led to further reduction of the wasm binary size to 147791 bytes as an additional beneficial effect on top of computational and memory allocation performance improvements.
Further adjustment of the "fast" `sqrt` function by tweaking data types does not lead to performance improvement.
**Definitions**:
```go
package mainimport "math"
func sqrt(v float64) float64 {
// from quake3 inverse sqrt algorithm
// ref: https://medium.com/@adrien.za/fast-inverse-square-root-in-go-and-javascript-for-fun-6b891e74e5a8
const magic64 = 0x5FE6EB50C7B537A9n2, th := v*0.5, float64(1.5)
b := math.Float64bits(v)
b = magic64 - (b >> 1)
f := math.Float64frombits(b)
f *= th - (n2 * f * f)
return f
}func sqrtV2(v uint32) float32 {
// from quake3 inverse sqrt algorithm
// ref: https://medium.com/@adrien.za/fast-inverse-square-root-in-go-and-javascript-for-fun-6b891e74e5a8
const magic = 0x5F375A86n2, th := float32(v)/2, float32(1.5)
b := magic - (v >> 1)
f := math.Float32frombits(b)
f *= th - (n2 * f * f)
return f
}
```**Tests**:
```go
package mainimport (
"testing"
)func benchmarkSQRT(i float64, b *testing.B) {
for n := 0; n < b.N; n++ {
sqrt(i)
}
}func benchmarkSQRTv2(i uint32, b *testing.B) {
for n := 0; n < b.N; n++ {
sqrtV2(i)
}
}func BenchmarkSQRT1(b *testing.B) { benchmarkSQRT(1, b) }
func BenchmarkSQRT10(b *testing.B) { benchmarkSQRT(10, b) }
func BenchmarkSQRT100(b *testing.B) { benchmarkSQRT(100, b) }
func BenchmarkSQRT1000(b *testing.B) { benchmarkSQRT(1000, b) }
func BenchmarkSQRT10000(b *testing.B) { benchmarkSQRT(10000, b) }
func BenchmarkSQRT100000(b *testing.B) { benchmarkSQRT(100000, b) }
func BenchmarkSQRT1000000(b *testing.B) { benchmarkSQRT(1000000, b) }func BenchmarkSQRTv2_1(b *testing.B) { benchmarkSQRTv2(1, b) }
func BenchmarkSQRTv2_10(b *testing.B) { benchmarkSQRTv2(10, b) }
func BenchmarkSQRTv2_100(b *testing.B) { benchmarkSQRTv2(100, b) }
func BenchmarkSQRTv2_1000(b *testing.B) { benchmarkSQRTv2(1000, b) }
func BenchmarkSQRTv2_10000(b *testing.B) { benchmarkSQRTv2(10000, b) }
func BenchmarkSQRTv2_100000(b *testing.B) { benchmarkSQRTv2(100000, b) }
func BenchmarkSQRTv2_1000000(b *testing.B) { benchmarkSQRTv2(1000000, b) }
```Benchmark results:
```bash
go test -bench=. -benchmem .
goos: darwin
goarch: arm64
pkg: srt
BenchmarkSQRT1-10 1000000000 0.3133 ns/op 0 B/op 0 allocs/op
BenchmarkSQRT10-10 1000000000 0.3111 ns/op 0 B/op 0 allocs/op
BenchmarkSQRT100-10 1000000000 0.3105 ns/op 0 B/op 0 allocs/op
BenchmarkSQRT1000-10 1000000000 0.3109 ns/op 0 B/op 0 allocs/op
BenchmarkSQRT10000-10 1000000000 0.3114 ns/op 0 B/op 0 allocs/op
BenchmarkSQRT100000-10 1000000000 0.3104 ns/op 0 B/op 0 allocs/op
BenchmarkSQRT1000000-10 1000000000 0.3126 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_1-10 1000000000 0.3109 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_10-10 1000000000 0.3105 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_100-10 1000000000 0.3105 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_1000-10 1000000000 0.3149 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_10000-10 1000000000 0.3114 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_100000-10 1000000000 0.3109 ns/op 0 B/op 0 allocs/op
BenchmarkSQRTv2_1000000-10 1000000000 0.3111 ns/op 0 B/op 0 allocs/op
PASS
ok srt 5.129s
```