From 60e0277eb466639dc083f00a73bb594055727a5f Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:23:15 +0100 Subject: [PATCH 1/4] cmd/keeper, cmd/utils, metrics: add zisk target using tamago --- build/checksums.txt | 5 ++ build/ci.go | 70 ++++++++++++++++++- cmd/keeper/dummy_fastcache/go.mod | 3 + cmd/keeper/dummy_fastcache/main.go | 13 ++++ cmd/keeper/getpayload_zisk.go | 32 +++++++++ cmd/keeper/go.mod | 5 +- cmd/keeper/go.sum | 4 -- cmd/keeper/stubs.go | 4 +- cmd/keeper/tamago_board.go | 24 +++++++ cmd/keeper/zisk/board.go | 106 ++++++++++++++++++++++++++++ cmd/keeper/zisk/cpu_riscv64.s | 18 +++++ cmd/keeper/zisk/hwinit1.s | 17 +++++ cmd/keeper/zisk/shutdown.s | 24 +++++++ metrics/cpu_enabled.go | 4 +- metrics/cputime_unix.go | 4 +- metrics/metrics.go | 100 --------------------------- metrics/metrics_notamago.go | 107 +++++++++++++++++++++++++++++ metrics/metrics_tamago.go | 12 ++++ 18 files changed, 437 insertions(+), 115 deletions(-) create mode 100644 cmd/keeper/dummy_fastcache/go.mod create mode 100644 cmd/keeper/dummy_fastcache/main.go create mode 100644 cmd/keeper/getpayload_zisk.go create mode 100644 cmd/keeper/tamago_board.go create mode 100644 cmd/keeper/zisk/board.go create mode 100644 cmd/keeper/zisk/cpu_riscv64.s create mode 100644 cmd/keeper/zisk/hwinit1.s create mode 100644 cmd/keeper/zisk/shutdown.s create mode 100644 metrics/metrics_notamago.go create mode 100644 metrics/metrics_tamago.go diff --git a/build/checksums.txt b/build/checksums.txt index 454efa93c4..d29088784e 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -49,6 +49,11 @@ ddc693d2d9d7cc671ebb72d1d50aa05670f95b059b7d90440611af57976871d5 go1.25.10.wind ca37af2dadd8544464f1a9ca7c3886499d1cdfcb263855d0a1d71f194b2bd222 go1.25.10.windows-amd64.zip 38be57e0398bd93673d65bcae6dc7ee3cf151d7038d0dba5c60a5153022872da go1.25.10.windows-arm64.zip +# version:tamago 1.25.6 +# https://github.com/usbarmory/tamago-go/releases/download/tamago-go1.25.6/ +fbab70549e5977150d9095829608b5b8c7a6226930f91beb8edd614f2a71348e tamago-go1.25.6.linux-amd64.tar.gz +8bfc5a4f2ff54625c3a26a1b8749a6639d9f85dbd2f687c41c932517c0814368 tamago-go1.25.6.linux-armv7l.tar.gz + # version:golangci 2.10.1 # https://github.com/golangci/golangci-lint/releases/ # https://github.com/golangci/golangci-lint/releases/download/v2.10.1 diff --git a/build/ci.go b/build/ci.go index 53ade2e1bf..d6095fd381 100644 --- a/build/ci.go +++ b/build/ci.go @@ -101,6 +101,13 @@ var ( GOARCH: "wasm", Tags: "womir", }, + { + Name: "zisk", + GOOS: "tamago", + GOARCH: "riscv64", + Tags: "tamago,zisk", + Env: map[string]string{"CGO_ENABLED": "0", "GO_EXTLINK_ENABLED": "0"}, + }, { Name: "wasm-js", GOOS: "js", @@ -290,16 +297,37 @@ func doInstallKeeper(cmdline []string) { flag.CommandLine.Parse(cmdline) env := build.Env() - // Configure the toolchain. + var ( + csdb *download.ChecksumDB + tamagoRoot string + ) tc := build.GoToolchain{} if *dlgo { - csdb := download.MustLoadChecksums("build/checksums.txt") - tc.Root = build.DownloadGo(csdb) + csdb = download.MustLoadChecksums("build/checksums.txt") } for _, target := range keeperTargets { log.Printf("Building keeper-%s", target.Name) + // Configure the toolchain. + if target.Name == "tamago" { + if runtime.GOOS != "linux" { + log.Printf("Skipping keeper-%s (tamago builds are only supported on linux hosts)", target.Name) + continue + } + if !*dlgo { + log.Printf("Skipping keeper-%s (tamago build requires -dlgo)", target.Name) + continue + } + + if tamagoRoot == "" { + tamagoRoot = downloadTamago(csdb) + } + tc.Root = tamagoRoot + } else if *dlgo { + tc.Root = build.DownloadGo(csdb) + } + // Configure the build. tc.GOARCH = target.GOARCH tc.GOOS = target.GOOS @@ -463,6 +491,42 @@ func downloadSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string return filepath.Join(cachedir, base) } +// downloadTamago downloads the tamago-go toolchain and returns its GOROOT. +func downloadTamago(csdb *download.ChecksumDB) string { + version, err := csdb.FindVersion("tamago") + if err != nil { + log.Fatal(err) + } + if runtime.GOOS != "linux" { + log.Printf("Skipping tamago toolchain download (unsupported host os: %s)", runtime.GOOS) + return "" + } + arch := runtime.GOARCH + if arch == "arm" { + arch = "armv7l" + } + file := fmt.Sprintf("tamago-go%s.%s-%s.tar.gz", version, runtime.GOOS, arch) + + ucache, err := os.UserCacheDir() + if err != nil { + log.Fatal(err) + } + dst := filepath.Join(ucache, file) + if err := csdb.DownloadFileFromKnownURL(dst); err != nil { + log.Fatal(err) + } + + toolRoot := filepath.Join(ucache, fmt.Sprintf("geth-tamago-go-%s-%s-%s", version, runtime.GOOS, arch)) + if err := build.ExtractArchive(dst, toolRoot); err != nil { + log.Fatal(err) + } + goroot, err := filepath.Abs(filepath.Join(toolRoot, "go")) + if err != nil { + log.Fatal(err) + } + return goroot +} + // doCheckGenerate ensures that re-generating generated files does not cause // any mutations in the source file tree. func doCheckGenerate() { diff --git a/cmd/keeper/dummy_fastcache/go.mod b/cmd/keeper/dummy_fastcache/go.mod new file mode 100644 index 0000000000..18062d6edd --- /dev/null +++ b/cmd/keeper/dummy_fastcache/go.mod @@ -0,0 +1,3 @@ +module github.com/ethereum/go-ethereum/cmd/keeper/dummy_fastcache + +go 1.24.0 diff --git a/cmd/keeper/dummy_fastcache/main.go b/cmd/keeper/dummy_fastcache/main.go new file mode 100644 index 0000000000..c4d5f7185e --- /dev/null +++ b/cmd/keeper/dummy_fastcache/main.go @@ -0,0 +1,13 @@ +package fastcache + +type Cache struct{} + +func (*Cache) Get(dst, k []byte) []byte { return nil } +func (*Cache) HasGet(dst, k []byte) ([]byte, bool) { return nil, false } +func (*Cache) Set(k, v []byte) {} +func (*Cache) Reset() {} +func (*Cache) Del([]byte) {} + +func New(int) *Cache { + return &Cache{} +} diff --git a/cmd/keeper/getpayload_zisk.go b/cmd/keeper/getpayload_zisk.go new file mode 100644 index 0000000000..05a96c5848 --- /dev/null +++ b/cmd/keeper/getpayload_zisk.go @@ -0,0 +1,32 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build zisk + +package main + +import ( + "unsafe" + + "github.com/ethereum/go-ethereum/cmd/keeper/zisk" +) + +func getInput() []byte { + inputPtr := unsafe.Pointer(uintptr(zisk.INPUT_ADDR + 8)) + inputSize := *(*uint64)(inputPtr) + inputDataPtr := unsafe.Pointer(uintptr(zisk.INPUT_ADDR + 16)) + return unsafe.Slice((*byte)(inputDataPtr), int(inputSize)) +} diff --git a/cmd/keeper/go.mod b/cmd/keeper/go.mod index b2caee8b63..2f2377948c 100644 --- a/cmd/keeper/go.mod +++ b/cmd/keeper/go.mod @@ -1,6 +1,6 @@ module github.com/ethereum/go-ethereum/cmd/keeper -go 1.24.0 +go 1.25.6 require ( github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 @@ -11,7 +11,6 @@ require ( github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect @@ -45,3 +44,5 @@ require ( ) replace github.com/ethereum/go-ethereum => ../../ + +replace github.com/VictoriaMetrics/fastcache => ./dummy_fastcache diff --git a/cmd/keeper/go.sum b/cmd/keeper/go.sum index 51a6a3fad2..005e5984b6 100644 --- a/cmd/keeper/go.sum +++ b/cmd/keeper/go.sum @@ -4,10 +4,6 @@ github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608 github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= -github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= diff --git a/cmd/keeper/stubs.go b/cmd/keeper/stubs.go index de7ee64353..d3e6c08444 100644 --- a/cmd/keeper/stubs.go +++ b/cmd/keeper/stubs.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !example && !ziren && !wasm && !womir -// +build !example,!ziren,!wasm,!womir +//go:build !example && !ziren && !wasm && !womiri && !zisk +// +build !example,!ziren,!wasm,!womiri,!zisk package main diff --git a/cmd/keeper/tamago_board.go b/cmd/keeper/tamago_board.go new file mode 100644 index 0000000000..fce5862183 --- /dev/null +++ b/cmd/keeper/tamago_board.go @@ -0,0 +1,24 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build tamago +// +build tamago + +package main + +import ( + _ "github.com/ethereum/go-ethereum/cmd/keeper/zisk" +) diff --git a/cmd/keeper/zisk/board.go b/cmd/keeper/zisk/board.go new file mode 100644 index 0000000000..72fb97e29e --- /dev/null +++ b/cmd/keeper/zisk/board.go @@ -0,0 +1,106 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build tamago && riscv64 + +package zisk + +import ( + "unsafe" +) + +const ( + // ZisK I/O addresses + INPUT_ADDR = 0x90000000 + QEMU_EXIT_ADDR = 0x100000 + QEMU_EXIT_CODE = 0x5555 + OUTPUT_ADDR = 0xa001_0000 + UART_ADDR = 0xa000_0200 + ARCH_ID_ZISK = 0xFFFEEEE // TEMPORARY // TODO register one + MAX_INPUT = 0x2000 + MAX_OUTPUT = 0x1_0000 +) + +var outputCount uint32 = 0 + +//go:linkname ramStart runtime.ramStart +var ramStart uint64 = 0xa0020000 // Match ZisK's RAM location + +//go:linkname ramSize runtime.ramSize +var ramSize uint64 = 0x1FFE0000 // Match ZisK's RAM size (~512MB) + +// ramStackOffset is always defined here as there's no linkramstackoffset build tag +// +//go:linkname ramStackOffset runtime.ramStackOffset +var ramStackOffset uint64 = 0x100000 // 1MB stack (matching ZisK) + +// Bloc sets the heap start address to bypass initBloc() +// +//go:linkname Bloc runtime.Bloc +var Bloc uintptr = 0xa0100000 // Start heap after stack (ramStart + ramStackOffset) + +// printk implementation for zkVM +// +//go:linkname printk runtime.printk +func printk(c byte) { + // TODO: This is a stub. Just write to the output address + // Write directly to OUTPUT_ADDR + // Format: [count:u32][data:bytes] + // First update the count at OUTPUT_ADDR + outputCount++ + *(*uint32)(unsafe.Pointer(uintptr(OUTPUT_ADDR))) = outputCount + + // Write the byte at OUTPUT_ADDR + 4 + (outputCount-1) + *(*byte)(unsafe.Pointer(uintptr(OUTPUT_ADDR + 4 + outputCount - 1))) = c +} + +// hwinit1 is now defined in hwinit1.s +// we use it to set A0/A1 registers to the input and output address + +// Use this as a stub timer. It is all single threaded, and there is no concept of time. +// This may return the cycle count in the future. +var timer int64 = 0 + +//go:linkname nanotime1 runtime.nanotime1 +func nanotime1() int64 { + // Return deterministic time for zkVM + // Could be based on instruction count or fixed increments + timer++ + return timer * 1000 +} + +//go:linkname initRNG runtime.initRNG +func initRNG() { + // Deterministic RNG initialization + // TODO: There is no "proper" rng so nothing to init. +} + +//go:linkname getRandomData runtime.getRandomData +func getRandomData(b []byte) { + // Deterministic "random" data + // In a real zkVM, this might come from the input + for i := range b { + b[i] = byte(i & 0xFF) + } +} + +// Init initializes the zkVM board +func Init() { + timer = 0 +} + +// Shutdown is defined in shutdown.s and uses ecall to exit +func Shutdown() diff --git a/cmd/keeper/zisk/cpu_riscv64.s b/cmd/keeper/zisk/cpu_riscv64.s new file mode 100644 index 0000000000..c2a15f1e38 --- /dev/null +++ b/cmd/keeper/zisk/cpu_riscv64.s @@ -0,0 +1,18 @@ +//go:build tamago && riscv64 + +#include "textflag.h" + +// Entry point - this is where execution starts +TEXT cpuinit(SB),NOSPLIT|NOFRAME,$0 + // Clear A0/A1 registers so runtime does not think we have + // argc/argv arguments + MOV $0, A0 + MOV $0, A1 + // Jump to tamago runtime for RISC-V + JMP runtime·rt0_riscv64_tamago(SB) + +// hwinit0 is called by the runtime during initialization +TEXT runtime·hwinit0(SB),NOSPLIT|NOFRAME,$0 + // Hardware initialization before runtime setup + // For zkVM, nothing special needed here + RET diff --git a/cmd/keeper/zisk/hwinit1.s b/cmd/keeper/zisk/hwinit1.s new file mode 100644 index 0000000000..0b2d4ffd44 --- /dev/null +++ b/cmd/keeper/zisk/hwinit1.s @@ -0,0 +1,17 @@ +//go:build tamago && riscv64 + +#include "textflag.h" + +#define INPUT_ADDR 0x90000000 +#define OUTPUT_ADDR 0xa0010000 + +// hwinit1 is called after basic runtime initialization +// We set A0/A1 here instead of in the emulator +TEXT runtime·hwinit1(SB),NOSPLIT|NOFRAME,$0 + // Set A0 to INPUT_ADDR + MOV $INPUT_ADDR, A0 + + // Set A1 to OUTPUT_ADDR + MOV $OUTPUT_ADDR, A1 + + RET diff --git a/cmd/keeper/zisk/shutdown.s b/cmd/keeper/zisk/shutdown.s new file mode 100644 index 0000000000..7d616278be --- /dev/null +++ b/cmd/keeper/zisk/shutdown.s @@ -0,0 +1,24 @@ +//go:build tamago && riscv64 && zisk + +#include "textflag.h" + +#define ARCH_ID_ZISK 0xFFFEEEE +#define QEMU_EXIT_ADDR 0x100000 +#define QEMU_EXIT_CODE 0x5555 + +// Shutdown triggers ZisK exit via ecall with a7=93 +TEXT ·Shutdown(SB),NOSPLIT|NOFRAME,$0 + // Read marchid CSR into A0 (CSRRS x10, 0xF12, x0) + WORD $0xF1202573 + MOV $ARCH_ID_ZISK, A1 // Load ZisK arch ID + BNE A0, A1, qemu_exit // If not, jump to qemu_exit + + MOV $93, A7 // CAUSE_EXIT = 93 + ECALL // System call to exit + RET // Should never reach here + +qemu_exit: + MOV $QEMU_EXIT_CODE, T0 // Load the exit code for QEMU + MOV $QEMU_EXIT_ADDR, T1 // Load the exit address for QEMU + ECALL // System call to exit QEMU + RET // Should never reach here diff --git a/metrics/cpu_enabled.go b/metrics/cpu_enabled.go index 37c23cad1a..1aab669cd4 100644 --- a/metrics/cpu_enabled.go +++ b/metrics/cpu_enabled.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !ios && !js && !wasip1 && !tinygo -// +build !ios,!js,!wasip1,!tinygo +//go:build !ios && !js && !wasip1 && !tinygo && !tamago +// +build !ios,!js,!wasip1,!tinygo,!tamago package metrics diff --git a/metrics/cputime_unix.go b/metrics/cputime_unix.go index 5db38b16a2..08b4eb47ae 100644 --- a/metrics/cputime_unix.go +++ b/metrics/cputime_unix.go @@ -14,8 +14,8 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !windows && !js && !wasip1 && !tinygo -// +build !windows,!js,!wasip1,!tinygo +//go:build !windows && !js && !wasip1 && !tinygo && !tamago +// +build !windows,!js,!wasip1,!tinygo,!tamago package metrics diff --git a/metrics/metrics.go b/metrics/metrics.go index 088948d403..147131a7e0 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -9,7 +9,6 @@ package metrics import ( "runtime/metrics" "runtime/pprof" - "time" ) var ( @@ -103,102 +102,3 @@ func readRuntimeStats(v *runtimeStats) { } } } - -// CollectProcessMetrics periodically collects various metrics about the running process. -func CollectProcessMetrics(refresh time.Duration) { - // Short circuit if the metrics system is disabled - if !metricsEnabled { - return - } - - // Create the various data collectors - var ( - cpustats = make([]CPUStats, 2) - diskstats = make([]DiskStats, 2) - rstats = make([]runtimeStats, 2) - ) - - // This scale factor is used for the runtime's time metrics. It's useful to convert to - // ns here because the runtime gives times in float seconds, but runtimeHistogram can - // only provide integers for the minimum and maximum values. - const secondsToNs = float64(time.Second) - - // Define the various metrics to collect - var ( - cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) - cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) - cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) - cpuSysLoadTotal = GetOrRegisterCounterFloat64("system/cpu/sysload/total", DefaultRegistry) - cpuSysWaitTotal = GetOrRegisterCounterFloat64("system/cpu/syswait/total", DefaultRegistry) - cpuProcLoadTotal = GetOrRegisterCounterFloat64("system/cpu/procload/total", DefaultRegistry) - cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) - cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) - cpuSchedLatency = getOrRegisterRuntimeHistogram("system/cpu/schedlatency", secondsToNs, nil) - memPauses = getOrRegisterRuntimeHistogram("system/memory/pauses", secondsToNs, nil) - memAllocs = GetOrRegisterMeter("system/memory/allocs", DefaultRegistry) - memFrees = GetOrRegisterMeter("system/memory/frees", DefaultRegistry) - memTotal = GetOrRegisterGauge("system/memory/held", DefaultRegistry) - heapUsed = GetOrRegisterGauge("system/memory/used", DefaultRegistry) - heapObjects = GetOrRegisterGauge("system/memory/objects", DefaultRegistry) - diskReads = GetOrRegisterMeter("system/disk/readcount", DefaultRegistry) - diskReadBytes = GetOrRegisterMeter("system/disk/readdata", DefaultRegistry) - diskReadBytesCounter = GetOrRegisterCounter("system/disk/readbytes", DefaultRegistry) - diskWrites = GetOrRegisterMeter("system/disk/writecount", DefaultRegistry) - diskWriteBytes = GetOrRegisterMeter("system/disk/writedata", DefaultRegistry) - diskWriteBytesCounter = GetOrRegisterCounter("system/disk/writebytes", DefaultRegistry) - ) - - var lastCollectTime time.Time - - // Iterate loading the different stats and updating the meters. - now, prev := 0, 1 - for ; ; now, prev = prev, now { - // Gather CPU times. - ReadCPUStats(&cpustats[now]) - collectTime := time.Now() - secondsSinceLastCollect := collectTime.Sub(lastCollectTime).Seconds() - lastCollectTime = collectTime - if secondsSinceLastCollect > 0 { - sysLoad := cpustats[now].GlobalTime - cpustats[prev].GlobalTime - sysWait := cpustats[now].GlobalWait - cpustats[prev].GlobalWait - procLoad := cpustats[now].LocalTime - cpustats[prev].LocalTime - // Convert to integer percentage. - cpuSysLoad.Update(int64(sysLoad / secondsSinceLastCollect * 100)) - cpuSysWait.Update(int64(sysWait / secondsSinceLastCollect * 100)) - cpuProcLoad.Update(int64(procLoad / secondsSinceLastCollect * 100)) - // increment counters (ms) - cpuSysLoadTotal.Inc(sysLoad) - cpuSysWaitTotal.Inc(sysWait) - cpuProcLoadTotal.Inc(procLoad) - } - - // Threads - cpuThreads.Update(int64(threadCreateProfile.Count())) - - // Go runtime metrics - readRuntimeStats(&rstats[now]) - - cpuGoroutines.Update(int64(rstats[now].Goroutines)) - cpuSchedLatency.update(rstats[now].SchedLatency) - memPauses.update(rstats[now].GCPauses) - - memAllocs.Mark(int64(rstats[now].GCAllocBytes - rstats[prev].GCAllocBytes)) - memFrees.Mark(int64(rstats[now].GCFreedBytes - rstats[prev].GCFreedBytes)) - - memTotal.Update(int64(rstats[now].MemTotal)) - heapUsed.Update(int64(rstats[now].MemTotal - rstats[now].HeapUnused - rstats[now].HeapFree - rstats[now].HeapReleased)) - heapObjects.Update(int64(rstats[now].HeapObjects)) - - // Disk - if ReadDiskStats(&diskstats[now]) == nil { - diskReads.Mark(diskstats[now].ReadCount - diskstats[prev].ReadCount) - diskReadBytes.Mark(diskstats[now].ReadBytes - diskstats[prev].ReadBytes) - diskWrites.Mark(diskstats[now].WriteCount - diskstats[prev].WriteCount) - diskWriteBytes.Mark(diskstats[now].WriteBytes - diskstats[prev].WriteBytes) - diskReadBytesCounter.Inc(diskstats[now].ReadBytes - diskstats[prev].ReadBytes) - diskWriteBytesCounter.Inc(diskstats[now].WriteBytes - diskstats[prev].WriteBytes) - } - - time.Sleep(refresh) - } -} diff --git a/metrics/metrics_notamago.go b/metrics/metrics_notamago.go new file mode 100644 index 0000000000..3aec2bd27b --- /dev/null +++ b/metrics/metrics_notamago.go @@ -0,0 +1,107 @@ +//go:build !tamago +// +build !tamago + +package metrics + +import ( + "time" +) + +// CollectProcessMetrics periodically collects various metrics about the running process. +func CollectProcessMetrics(refresh time.Duration) { + // Short circuit if the metrics system is disabled + if !metricsEnabled { + return + } + + // Create the various data collectors + var ( + cpustats = make([]CPUStats, 2) + diskstats = make([]DiskStats, 2) + rstats = make([]runtimeStats, 2) + ) + + // This scale factor is used for the runtime's time metrics. It's useful to convert to + // ns here because the runtime gives times in float seconds, but runtimeHistogram can + // only provide integers for the minimum and maximum values. + const secondsToNs = float64(time.Second) + + // Define the various metrics to collect + var ( + cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) + cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) + cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) + cpuSysLoadTotal = GetOrRegisterCounterFloat64("system/cpu/sysload/total", DefaultRegistry) + cpuSysWaitTotal = GetOrRegisterCounterFloat64("system/cpu/syswait/total", DefaultRegistry) + cpuProcLoadTotal = GetOrRegisterCounterFloat64("system/cpu/procload/total", DefaultRegistry) + cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) + cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) + cpuSchedLatency = getOrRegisterRuntimeHistogram("system/cpu/schedlatency", secondsToNs, nil) + memPauses = getOrRegisterRuntimeHistogram("system/memory/pauses", secondsToNs, nil) + memAllocs = GetOrRegisterMeter("system/memory/allocs", DefaultRegistry) + memFrees = GetOrRegisterMeter("system/memory/frees", DefaultRegistry) + memTotal = GetOrRegisterGauge("system/memory/held", DefaultRegistry) + heapUsed = GetOrRegisterGauge("system/memory/used", DefaultRegistry) + heapObjects = GetOrRegisterGauge("system/memory/objects", DefaultRegistry) + diskReads = GetOrRegisterMeter("system/disk/readcount", DefaultRegistry) + diskReadBytes = GetOrRegisterMeter("system/disk/readdata", DefaultRegistry) + diskReadBytesCounter = GetOrRegisterCounter("system/disk/readbytes", DefaultRegistry) + diskWrites = GetOrRegisterMeter("system/disk/writecount", DefaultRegistry) + diskWriteBytes = GetOrRegisterMeter("system/disk/writedata", DefaultRegistry) + diskWriteBytesCounter = GetOrRegisterCounter("system/disk/writebytes", DefaultRegistry) + ) + + var lastCollectTime time.Time + + // Iterate loading the different stats and updating the meters. + now, prev := 0, 1 + for ; ; now, prev = prev, now { + // Gather CPU times. + ReadCPUStats(&cpustats[now]) + collectTime := time.Now() + secondsSinceLastCollect := collectTime.Sub(lastCollectTime).Seconds() + lastCollectTime = collectTime + if secondsSinceLastCollect > 0 { + sysLoad := cpustats[now].GlobalTime - cpustats[prev].GlobalTime + sysWait := cpustats[now].GlobalWait - cpustats[prev].GlobalWait + procLoad := cpustats[now].LocalTime - cpustats[prev].LocalTime + // Convert to integer percentage. + cpuSysLoad.Update(int64(sysLoad / secondsSinceLastCollect * 100)) + cpuSysWait.Update(int64(sysWait / secondsSinceLastCollect * 100)) + cpuProcLoad.Update(int64(procLoad / secondsSinceLastCollect * 100)) + // increment counters (ms) + cpuSysLoadTotal.Inc(sysLoad) + cpuSysWaitTotal.Inc(sysWait) + cpuProcLoadTotal.Inc(procLoad) + } + + // Threads + cpuThreads.Update(int64(threadCreateProfile.Count())) + + // Go runtime metrics + readRuntimeStats(&rstats[now]) + + cpuGoroutines.Update(int64(rstats[now].Goroutines)) + cpuSchedLatency.update(rstats[now].SchedLatency) + memPauses.update(rstats[now].GCPauses) + + memAllocs.Mark(int64(rstats[now].GCAllocBytes - rstats[prev].GCAllocBytes)) + memFrees.Mark(int64(rstats[now].GCFreedBytes - rstats[prev].GCFreedBytes)) + + memTotal.Update(int64(rstats[now].MemTotal)) + heapUsed.Update(int64(rstats[now].MemTotal - rstats[now].HeapUnused - rstats[now].HeapFree - rstats[now].HeapReleased)) + heapObjects.Update(int64(rstats[now].HeapObjects)) + + // Disk + if ReadDiskStats(&diskstats[now]) == nil { + diskReads.Mark(diskstats[now].ReadCount - diskstats[prev].ReadCount) + diskReadBytes.Mark(diskstats[now].ReadBytes - diskstats[prev].ReadBytes) + diskWrites.Mark(diskstats[now].WriteCount - diskstats[prev].WriteCount) + diskWriteBytes.Mark(diskstats[now].WriteBytes - diskstats[prev].WriteBytes) + diskReadBytesCounter.Inc(diskstats[now].ReadBytes - diskstats[prev].ReadBytes) + diskWriteBytesCounter.Inc(diskstats[now].WriteBytes - diskstats[prev].WriteBytes) + } + + time.Sleep(refresh) + } +} diff --git a/metrics/metrics_tamago.go b/metrics/metrics_tamago.go new file mode 100644 index 0000000000..f09620df0b --- /dev/null +++ b/metrics/metrics_tamago.go @@ -0,0 +1,12 @@ +//go:build tamago +// +build tamago + +package metrics + +import ( + "time" +) + +// CollectProcessMetrics periodically collects various metrics about the running process. +func CollectProcessMetrics(time.Duration) { +} From b48d69fac1a89deaeab3fd05c1a3575b25629050 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:59:41 +0200 Subject: [PATCH 2/4] fix linter --- cmd/keeper/go.mod | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/keeper/go.mod b/cmd/keeper/go.mod index 2f2377948c..0745081fe4 100644 --- a/cmd/keeper/go.mod +++ b/cmd/keeper/go.mod @@ -11,6 +11,7 @@ require ( github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect From 10113ba6b1847c46009d274483d5fe73bad66774 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:02:18 +0200 Subject: [PATCH 3/4] fix the keeper-zisk build --- build/ci.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/build/ci.go b/build/ci.go index d6095fd381..a6c279d0e3 100644 --- a/build/ci.go +++ b/build/ci.go @@ -297,10 +297,7 @@ func doInstallKeeper(cmdline []string) { flag.CommandLine.Parse(cmdline) env := build.Env() - var ( - csdb *download.ChecksumDB - tamagoRoot string - ) + var csdb *download.ChecksumDB tc := build.GoToolchain{} if *dlgo { csdb = download.MustLoadChecksums("build/checksums.txt") @@ -310,7 +307,7 @@ func doInstallKeeper(cmdline []string) { log.Printf("Building keeper-%s", target.Name) // Configure the toolchain. - if target.Name == "tamago" { + if target.GOOS == "tamago" { if runtime.GOOS != "linux" { log.Printf("Skipping keeper-%s (tamago builds are only supported on linux hosts)", target.Name) continue @@ -320,10 +317,7 @@ func doInstallKeeper(cmdline []string) { continue } - if tamagoRoot == "" { - tamagoRoot = downloadTamago(csdb) - } - tc.Root = tamagoRoot + tc.Root = downloadTamago(csdb) } else if *dlgo { tc.Root = build.DownloadGo(csdb) } @@ -520,7 +514,7 @@ func downloadTamago(csdb *download.ChecksumDB) string { if err := build.ExtractArchive(dst, toolRoot); err != nil { log.Fatal(err) } - goroot, err := filepath.Abs(filepath.Join(toolRoot, "go")) + goroot, err := filepath.Abs(filepath.Join(toolRoot, "usr/local/tamago-go")) if err != nil { log.Fatal(err) } From 2a5688bd4f4b169fc061846f6233972571fa797e Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:56:12 +0200 Subject: [PATCH 4/4] hardcode linker script --- build/ci.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build/ci.go b/build/ci.go index a6c279d0e3..dacdc0c0d7 100644 --- a/build/ci.go +++ b/build/ci.go @@ -360,12 +360,12 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string, t ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitCommit="+env.Commit) ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitDate="+env.Date) } + switch targetOS { // Strip DWARF on darwin. This used to be required for certain things, // and there is no downside to this, so we just keep doing it. - if targetOS == "darwin" { + case "darwin": ld = append(ld, "-s") - } - if targetOS == "linux" { + case "linux": // Enforce the stacksize to 8M, which is the case on most platforms apart from // alpine Linux. // See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options @@ -380,6 +380,8 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string, t buildTags = append(buildTags, "osusergo", "netgo") } ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'") + case "tamago": + ld = append(ld, "-T", "0x80010000", "-R", "0x1000") } // TODO(gballet): revisit after the input api has been defined if runtime.GOARCH == "wasm" {