Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

encoding build statusGo Report CardGoDoc

Go package containing implementations of encoders and decoders for various data formats.

Motivation

At Segment, we do a lot of marshaling and unmarshaling of data when sending, queuing, or storing messages. The resources we need to provision on the infrastructure are directly related to the type and amount of data that we are processing. At the scale we operate at, the tools we choose to build programs can have a large impact on the efficiency of our systems. It is important to explore alternative approaches when we reach the limits of the code we use.

This repository includes experiments for Go packages for marshaling and unmarshaling data in various formats. While the focus is on providing a high performance library, we also aim for very low development and maintenance overhead by implementing APIs that can be used as drop-in replacements for the default solutions.

Requirements and Maintenance Schedule

This package has no dependencies outside of the core runtime of Go. It requires a recent version of Go.

This package follows the same maintenance schedule as the Go project, meaning that issues relating to versions of Go which aren't supported by the Go team, or versions of this package which are older than 1 year, are unlikely to be considered.

Additionally, we have fuzz tests which aren't a runtime required dependency but will be pulled in when running go mod tidy. Please don't include these go.mod updates in change requests.

encoding/json GoDoc

More details about how this package achieves a lower CPU and memory footprint can be found in the package README.

The json sub-package provides a re-implementation of the functionalities offered by the standard library's encoding/json package, with a focus on lowering the CPU and memory footprint of the code.

The exported API of this package mirrors the standard library's encoding/json package, the only change needed to take advantage of the performance improvements is the import path of the json package, from:

import (
"encoding/json"
)

to

import (
"github.com/segmentio/encoding/json"
)

The improvement can be significant for code that heavily relies on serializing and deserializing JSON payloads. The CI pipeline runs benchmarks to compare the performance of the package with the standard library and other popular alternatives; here's an overview of the results:

Comparing to encoding/json (v1.16.2)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.40ms ± 2% 3.82ms ± 1% -40.29% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 28.1ms ± 3% 5.6ms ± 3% -80.21% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 303MB/s ± 2% 507MB/s ± 1% +67.47% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 69.2MB/s ± 3% 349.6MB/s ± 3% +405.42% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 0.00B 0.00B ~ (all equal)
Unmarshal/*json.codeResponse2 1.80MB ± 1% 0.02MB ± 0% -99.14% (p=0.016 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 0.00 0.00 ~ (all equal)
Unmarshal/*json.codeResponse2 76.6k ± 0% 0.1k ± 3% -99.92% (p=0.008 n=5+5)

Benchmarks were run on a Core i9-8950HK CPU @ 2.90GHz.

Comparing to github.com/json-iterator/go (v1.1.10)

name old time/op new time/op delta
Marshal/*json.codeResponse2 6.19ms ± 3% 3.82ms ± 1% -38.26% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 8.52ms ± 3% 5.55ms ± 3% -34.84% (p=0.008 n=5+5)
name old speed new speed delta
Marshal/*json.codeResponse2 313MB/s ± 3% 507MB/s ± 1% +61.91% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 228MB/s ± 3% 350MB/s ± 3% +53.50% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Marshal/*json.codeResponse2 8.00B ± 0% 0.00B -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 1.05MB ± 0% 0.02MB ± 0% -98.53% (p=0.000 n=5+4)
name old allocs/op new allocs/op delta
Marshal/*json.codeResponse2 1.00 ± 0% 0.00 -100.00% (p=0.008 n=5+5)
Unmarshal/*json.codeResponse2 37.2k ± 0% 0.1k ± 3% -99.83% (p=0.008 n=5+5)

Although this package aims to be a drop-in replacement of encoding/json, it does not guarantee the same error messages. It will error in the same cases as the standard library, but the exact error message may be different.

encoding/iso8601 GoDoc

The iso8601 sub-package exposes APIs to efficiently deal with with string representations of iso8601 dates.

Data formats like JSON have no syntaxes to represent dates, they are usually serialized and represented as a string value. In our experience, we often have to check whether a string value looks like a date, and either construct a time.Time by parsing it or simply treat it as a string. This check can be done by attempting to parse the value, and if it fails fallback to using the raw string. Unfortunately, while the happy path for time.Parse is fairly efficient, constructing errors is much slower and has a much bigger memory footprint.

We've developed fast iso8601 validation functions that cause no heap allocations to remediate this problem. We added a validation step to determine whether the value is a date representation or a simple string. This reduced CPU and memory usage by 5% in some programs that were doing time.Parse calls on very hot code paths.

About

Go package containing implementations of efficient encoding, decoding, and validation APIs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages