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) {
+}