279 lines
7.1 KiB
Go
279 lines
7.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type input struct {
|
|
Ticks string `json:"ticks"`
|
|
}
|
|
type sample struct {
|
|
Elapsed int64 `json:"elapsed_ns"`
|
|
Checksum int64 `json:"checksum"`
|
|
}
|
|
type record struct {
|
|
First int64
|
|
Second int64
|
|
Third int64
|
|
}
|
|
|
|
type ownedRecord struct {
|
|
Name string
|
|
Tags []string
|
|
Count int64
|
|
}
|
|
|
|
func inspectOwned(row ownedRecord) int64 {
|
|
return checkedAdd(checkedAdd(row.Count, int64(utf8.RuneCountInString(row.Name))), int64(len(row.Tags)))
|
|
}
|
|
|
|
func forwardOwned(row ownedRecord) int64 {
|
|
return inspectOwned(row)
|
|
}
|
|
|
|
func checkedAdd(total, value int64) int64 {
|
|
if value > 0 && total > math.MaxInt64-value {
|
|
panic("overflow")
|
|
}
|
|
return total + value
|
|
}
|
|
|
|
func measure(operation string, ticks string) sample {
|
|
source := []byte(ticks)
|
|
total := int64(0)
|
|
elapsed := int64(0)
|
|
switch operation {
|
|
case "record_update":
|
|
var values []int64
|
|
count := int64(0)
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
values = append(values, int64(value))
|
|
count = checkedAdd(count, 1)
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for _, value := range values {
|
|
total = checkedAdd(total, value)
|
|
}
|
|
total = checkedAdd(total, count) - int64(len(values))
|
|
case "record_inspect":
|
|
var values []int64
|
|
count := int64(0)
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
count = checkedAdd(int64(len(values)), 1)
|
|
values = append(values, int64(value))
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for _, value := range values {
|
|
total = checkedAdd(total, value)
|
|
}
|
|
total = checkedAdd(total, count) - int64(len(values))
|
|
case "map_lookup":
|
|
values := make(map[int64]int64, len(source))
|
|
for index, value := range source {
|
|
values[int64(index)] = int64(value)
|
|
}
|
|
index := int64(0)
|
|
begin := time.Now()
|
|
for range source {
|
|
total = checkedAdd(total, values[index])
|
|
index = checkedAdd(index, 1)
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
case "text_equal", "text_contains":
|
|
rows := make([][2]string, len(source))
|
|
for index, value := range source {
|
|
left := "compare-value-" + strconv.Itoa(int(value))
|
|
rows[index] = [2]string{left, strings.ToLower(strings.ToUpper(left))}
|
|
}
|
|
begin := time.Now()
|
|
if operation == "text_equal" {
|
|
for _, row := range rows {
|
|
matched := int64(0)
|
|
if row[0] == row[1] {
|
|
matched = 120
|
|
}
|
|
total = checkedAdd(total, matched)
|
|
}
|
|
} else {
|
|
for _, row := range rows {
|
|
matched := int64(0)
|
|
if strings.Contains(row[0], row[1]) {
|
|
matched = 120
|
|
}
|
|
total = checkedAdd(total, matched)
|
|
}
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
runtime.KeepAlive(rows)
|
|
total = checkedAdd(total, int64(len(rows))) - int64(len(source))
|
|
case "map_text_lookup":
|
|
keys := make([]string, len(source))
|
|
values := make(map[string]int64, len(source))
|
|
for index, value := range source {
|
|
key := "lookup-key-" + strconv.Itoa(index)
|
|
keys[index] = key
|
|
values[key] = int64(value)
|
|
}
|
|
begin := time.Now()
|
|
for _, key := range keys {
|
|
total = checkedAdd(total, values[key])
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
runtime.KeepAlive(values)
|
|
runtime.KeepAlive(keys)
|
|
total = checkedAdd(total, int64(len(keys))) - int64(len(source))
|
|
case "call_read":
|
|
rows := make([]ownedRecord, 0, len(source))
|
|
for _, value := range source {
|
|
name := "row-value-" + strconv.Itoa(int(value))
|
|
rows = append(rows, ownedRecord{name, []string{name}, int64(value) - int64(utf8.RuneCountInString(name)) - 1})
|
|
}
|
|
begin := time.Now()
|
|
for _, row := range rows {
|
|
total = checkedAdd(total, forwardOwned(row))
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
case "float":
|
|
floating := 0.0
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
floating += float64(value)
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
total = int64(floating)
|
|
case "bytes_concat":
|
|
chunks := make([][]byte, len(source))
|
|
for index := range source {
|
|
chunks[index] = source[index : index+1]
|
|
}
|
|
var output []byte
|
|
begin := time.Now()
|
|
for _, chunk := range chunks {
|
|
output = append(output, chunk...)
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for _, value := range output {
|
|
total = checkedAdd(total, int64(value))
|
|
}
|
|
case "text_concat":
|
|
chunks := strings.Split(ticks, ",")
|
|
begin := time.Now()
|
|
var output strings.Builder
|
|
for _, chunk := range chunks {
|
|
output.WriteString(chunk)
|
|
}
|
|
joined := output.String()
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for index := 0; index < len(joined); index++ {
|
|
total = checkedAdd(total, int64(joined[index]))
|
|
}
|
|
case "integer":
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
total = checkedAdd(total, int64(value))
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
case "list":
|
|
var values []int64
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
values = append(values, int64(value))
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for _, value := range values {
|
|
total = checkedAdd(total, value)
|
|
}
|
|
case "map":
|
|
values := make(map[int64]int64)
|
|
var order []int64
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
key := int64(len(values))
|
|
values[key] = int64(value)
|
|
order = append(order, key)
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for _, key := range order {
|
|
total = checkedAdd(total, values[key])
|
|
}
|
|
case "list_read":
|
|
var values []int64
|
|
for _, value := range source {
|
|
values = append(values, int64(value))
|
|
}
|
|
begin := time.Now()
|
|
for _, value := range values {
|
|
total = checkedAdd(total, value)
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
case "map_read":
|
|
values := make(map[int64]int64)
|
|
var order []int64
|
|
for _, value := range source {
|
|
key := int64(len(values))
|
|
values[key] = int64(value)
|
|
order = append(order, key)
|
|
}
|
|
begin := time.Now()
|
|
for _, key := range order {
|
|
total = checkedAdd(total, values[key])
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
case "list_record":
|
|
var values []record
|
|
begin := time.Now()
|
|
for _, value := range source {
|
|
values = append(values, record{int64(value), 0, 0})
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
for _, value := range values {
|
|
total = checkedAdd(total, checkedAdd(checkedAdd(value.First, value.Second), value.Third))
|
|
}
|
|
case "list_record_read":
|
|
var values []record
|
|
for _, value := range source {
|
|
values = append(values, record{int64(value), 0, 0})
|
|
}
|
|
begin := time.Now()
|
|
for _, value := range values {
|
|
total = checkedAdd(total, checkedAdd(checkedAdd(value.First, value.Second), value.Third))
|
|
}
|
|
elapsed = time.Since(begin).Nanoseconds()
|
|
default:
|
|
panic("unknown kernel")
|
|
}
|
|
return sample{elapsed, total}
|
|
}
|
|
|
|
func main() {
|
|
var arguments input
|
|
if err := json.Unmarshal([]byte(os.Args[2]), &arguments); err != nil {
|
|
panic(err)
|
|
}
|
|
var result any
|
|
if operation, continuous := strings.CutPrefix(os.Args[1], "continuous_"); continuous {
|
|
samples := make([]sample, 0, 10)
|
|
for range 10 {
|
|
samples = append(samples, measure(operation, arguments.Ticks))
|
|
}
|
|
result = samples
|
|
} else {
|
|
result = measure(os.Args[1], arguments.Ticks)
|
|
}
|
|
output, err := json.Marshal(result)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Println(string(output))
|
|
}
|